From 8b6ba0db54053a69203ad57679b250bf4e3e2d07 Mon Sep 17 00:00:00 2001 From: edwardgou-sentry <83961295+edwardgou-sentry@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:11:11 -0400 Subject: [PATCH 001/305] fix(performance): Add spans-first-ui flag to enable starfish/performance module views in ui (#2993) Adds spans-first-ui flag to enable displaying starfish/performance modules in ui --- sentry/sentry.conf.example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 5247cca12db..40e2728569f 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -308,6 +308,7 @@ def get_internal_network(): "organizations:mobile-ttid-ttfd-contribution", "organizations:starfish-mobile-appstart", "organizations:standalone-span-ingestion", + "organizations:spans-first-ui", ) # starfish related flags } ) From ebf887c931b0c6c02906fb9d2bd01e17bb3f1967 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Tue, 23 Apr 2024 13:28:01 -0700 Subject: [PATCH 002/305] Tweak e2e test github action (#2987) --- .github/workflows/test.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b264e451441..fd1146aa16a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,18 +24,6 @@ jobs: with: path: self-hosted - - name: Get Compose - run: | - # Always remove `docker compose` support as that's the newer version - # and comes installed by default nowadays. - sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" - # Docker Compose v1 is installed here, remove it - sudo rm -f "/usr/local/bin/docker-compose" - sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" - sudo mkdir -p "/usr/local/lib/docker/cli-plugins" - sudo curl -L https://github.com/docker/compose/releases/download/v2.7.0/docker-compose-`uname -s`-`uname -m` -o "/usr/local/lib/docker/cli-plugins/docker-compose" - sudo chmod +x "/usr/local/lib/docker/cli-plugins/docker-compose" - - name: End to end tests uses: getsentry/action-self-hosted-e2e-tests@main with: From 6c67717fc530145514198143007af1c7ff5b03a3 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Wed, 24 Apr 2024 08:59:42 -0700 Subject: [PATCH 003/305] Sampling: Run e2e tests every 5 minutes (#2994) run tests every 5 minutes --- .github/workflows/sample-test-runs.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/sample-test-runs.yml diff --git a/.github/workflows/sample-test-runs.yml b/.github/workflows/sample-test-runs.yml new file mode 100644 index 00000000000..a3c24e4f7c0 --- /dev/null +++ b/.github/workflows/sample-test-runs.yml @@ -0,0 +1,23 @@ +name: Test +on: + schedule: + # kick off a job every 5 minutes + - cron: "*/5 * * * *" +defaults: + run: + shell: bash +jobs: + e2e-test: + if: github.repository_owner == 'getsentry' + runs-on: ubuntu-22.04 + name: "Sentry self-hosted end-to-end tests" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + path: self-hosted + + - name: End to end tests + uses: getsentry/action-self-hosted-e2e-tests@main + with: + project_name: self-hosted From 6f91da5ea5fd930223e656bf2f238e2357a2eeb1 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Fri, 26 Apr 2024 11:27:58 -0700 Subject: [PATCH 004/305] Fix master test failures (#3000) * fix for tests? * fix tests on master --- _integration-test/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_integration-test/conftest.py b/_integration-test/conftest.py index 9d2a0fff236..b36097d6056 100644 --- a/_integration-test/conftest.py +++ b/_integration-test/conftest.py @@ -40,7 +40,7 @@ def configure_self_hosted_environment(request): #!/bin/bash touch /created-by-enhance-image apt-get update -apt-get install -y gcc libsasl2-dev python-dev libldap2-dev libssl-dev +apt-get install -y gcc libsasl2-dev python-dev-is-python3 libldap2-dev libssl-dev """ with open("sentry/enhance-image.sh", "w") as script_file: @@ -52,7 +52,7 @@ def configure_self_hosted_environment(request): with open("sentry/requirements.txt", "w") as req_file: req_file.write("python-ldap\n") os.environ["MINIMIZE_DOWNTIME"] = "1" - subprocess.run(["./install.sh"], check=True) + subprocess.run(["./install.sh"], check=True, capture_output=True) # Create test user subprocess.run( [ From f84bb3d8e8e5f185dfb952b220a071efcbc8f070 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Fri, 26 Apr 2024 13:19:16 -0700 Subject: [PATCH 005/305] Revert "Sampling: Run e2e tests every 5 minutes" (#2999) Revert "Sampling: Run e2e tests every 5 minutes (#2994)" This reverts commit 6c67717fc530145514198143007af1c7ff5b03a3. --- .github/workflows/sample-test-runs.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .github/workflows/sample-test-runs.yml diff --git a/.github/workflows/sample-test-runs.yml b/.github/workflows/sample-test-runs.yml deleted file mode 100644 index a3c24e4f7c0..00000000000 --- a/.github/workflows/sample-test-runs.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Test -on: - schedule: - # kick off a job every 5 minutes - - cron: "*/5 * * * *" -defaults: - run: - shell: bash -jobs: - e2e-test: - if: github.repository_owner == 'getsentry' - runs-on: ubuntu-22.04 - name: "Sentry self-hosted end-to-end tests" - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - path: self-hosted - - - name: End to end tests - uses: getsentry/action-self-hosted-e2e-tests@main - with: - project_name: self-hosted From 3150263073614f76054c2fcc4fce4ff4cee483bd Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Mon, 29 Apr 2024 10:47:32 -0700 Subject: [PATCH 006/305] Edit test file name (#3002) edit file name --- .../custom-ca-roots/{test.py => custom-ca-roots-test.py} | 0 _integration-test/test_run.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename _integration-test/custom-ca-roots/{test.py => custom-ca-roots-test.py} (100%) diff --git a/_integration-test/custom-ca-roots/test.py b/_integration-test/custom-ca-roots/custom-ca-roots-test.py similarity index 100% rename from _integration-test/custom-ca-roots/test.py rename to _integration-test/custom-ca-roots/custom-ca-roots-test.py diff --git a/_integration-test/test_run.py b/_integration-test/test_run.py index 84bc027c2b3..2b5774832b9 100644 --- a/_integration-test/test_run.py +++ b/_integration-test/test_run.py @@ -313,7 +313,7 @@ def test_custom_certificate_authorities(): with open(fake_test_cert_path, "wb") as cert_file: cert_file.write(fake_test_cert.public_bytes(serialization.Encoding.PEM)) shutil.copyfile( - "_integration-test/custom-ca-roots/test.py", + "_integration-test/custom-ca-roots/custom-ca-roots-test.py", "sentry/test-custom-ca-roots.py", ) From 935a68382beb8eaa8de1e33041076073595557b9 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 30 Apr 2024 18:05:37 +0000 Subject: [PATCH 007/305] release: 24.4.2 --- .env | 10 +++++----- CHANGELOG.md | 14 ++++++++++++++ README.md | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 8e54a3df2c9..b9b1a87a522 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.4.2 +SNUBA_IMAGE=getsentry/snuba:24.4.2 +RELAY_IMAGE=getsentry/relay:24.4.2 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.4.2 +VROOM_IMAGE=getsentry/vroom:24.4.2 WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/CHANGELOG.md b/CHANGELOG.md index d3bcd69c13d..735a055ac5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 24.4.2 + +### Various fixes & improvements + +- Edit test file name (#3002) by @hubertdeng123 +- Revert "Sampling: Run e2e tests every 5 minutes" (#2999) by @hubertdeng123 +- Fix master test failures (#3000) by @hubertdeng123 +- Sampling: Run e2e tests every 5 minutes (#2994) by @hubertdeng123 +- Tweak e2e test github action (#2987) by @hubertdeng123 +- fix(performance): Add spans-first-ui flag to enable starfish/performance module views in ui (#2993) by @edwardgou-sentry +- Bump docker compose version in CI (#2980) by @hubertdeng123 +- Upgrade postgres to 14.11 (#2975) by @mdtro +- Add workstation configuration (#2968) by @azaslavsky + ## 24.4.1 ### Various fixes & improvements diff --git a/README.md b/README.md index 13f4f2b8934..233f9a8f6b7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry nightly +# Self-Hosted Sentry 24.4.2 Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From aa5a50a9c0c1ee915362938b10a8ac94b8592d4b Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 30 Apr 2024 18:42:25 +0000 Subject: [PATCH 008/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index b9b1a87a522..8e54a3df2c9 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.4.2 -SNUBA_IMAGE=getsentry/snuba:24.4.2 -RELAY_IMAGE=getsentry/relay:24.4.2 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.4.2 -VROOM_IMAGE=getsentry/vroom:24.4.2 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/README.md b/README.md index 233f9a8f6b7..13f4f2b8934 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry 24.4.2 +# Self-Hosted Sentry nightly Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From 6db528d71afbe705b47c6100f9e161a7f2a57106 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Tue, 30 Apr 2024 12:32:22 -0700 Subject: [PATCH 009/305] Bump kafka and zookeeper versions (#2988) * bump kafka and zookeeper versions --- docker-compose.yml | 4 ++-- install.sh | 1 + install/update-docker-volume-permissions.sh | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 install/update-docker-volume-permissions.sh diff --git a/docker-compose.yml b/docker-compose.yml index 0736bdb63c0..c7457b3f9eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -160,7 +160,7 @@ services: target: /opt/sentry/ zookeeper: <<: *restart_policy - image: "confluentinc/cp-zookeeper:5.5.7" + image: "confluentinc/cp-zookeeper:7.6.1" environment: ZOOKEEPER_CLIENT_PORT: "2181" CONFLUENT_SUPPORT_METRICS_ENABLE: "false" @@ -184,7 +184,7 @@ services: depends_on: zookeeper: <<: *depends_on-healthy - image: "confluentinc/cp-kafka:5.5.7" + image: "confluentinc/cp-kafka:7.6.1" environment: KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092" diff --git a/install.sh b/install.sh index 78a96fece61..53c80cdeff5 100755 --- a/install.sh +++ b/install.sh @@ -21,6 +21,7 @@ source install/check-minimum-requirements.sh # Let's go! Start impacting things. source install/turn-things-off.sh +source install/update-docker-volume-permissions.sh source install/create-docker-volumes.sh source install/ensure-files-from-examples.sh source install/check-memcached-backend.sh diff --git a/install/update-docker-volume-permissions.sh b/install/update-docker-volume-permissions.sh new file mode 100644 index 00000000000..463e01773e0 --- /dev/null +++ b/install/update-docker-volume-permissions.sh @@ -0,0 +1,15 @@ +echo "${_group}Ensuring Kafka and Zookeeper volumes have correct permissions ..." + +# Only supporting platforms on linux x86 platforms and not apple silicon. I'm assuming that folks using apple silicon are doing it for dev purposes and it's difficult +# to change permissions of docker volumes since it is run in a VM. +if [[ "$DOCKER_PLATFORM" = "linux/amd64" && -n "$(docker volume ls -q -f name=sentry-zookeeper)" && -n "$(docker volume ls -q -f name=sentry-kafka)" ]]; then + zookeeper_data_dir="/var/lib/docker/volumes/sentry-zookeeper/_data" + kafka_data_dir="/var/lib/docker/volumes/sentry-kafka/_data" + zookeeper_log_data_dir="/var/lib/docker/volumes/sentry-self-hosted_sentry-zookeeper-log/_data" + chmod -R a+w $zookeeper_data_dir $kafka_data_dir $zookeeper_log_data_dir && returncode=$? || returncode=$? + if [[ $returncode == "1" ]]; then + echo "WARNING: Error when setting appropriate permissions for zookeeper, kafka, and zookeeper log docker volumes. This may corrupt your self-hosted install. See https://github.com/confluentinc/kafka-images/issues/127 for context on why this was added." + fi +fi + +echo "${_endgroup}" From 9e36d2f57a431a236f86a4fcd38125faf7721232 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Thu, 2 May 2024 13:04:34 -0700 Subject: [PATCH 010/305] Add upgrade test (#3012) * add upgrade test --- .github/workflows/test.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fd1146aa16a..e2303cd97d3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,6 +40,43 @@ jobs: - name: Unit Tests run: ./unit-test.sh + upgrade-test: + if: github.repository_owner == 'getsentry' + runs-on: ubuntu-22.04 + name: "Sentry upgrade test" + env: + REPORT_SELF_HOSTED_ISSUES: 0 + steps: + - name: Get latest self-hosted release version + run: | + LATEST_TAG=$(curl -s https://api.github.com/repos/getsentry/self-hosted/releases/latest | jq -r '.tag_name') + echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV + + - name: Checkout latest release + uses: actions/checkout@v4 + with: + ref: ${{ env.LATEST_TAG }} + + - name: Get Compose + run: | + # Docker Compose v1 is installed here, remove it + sudo rm -f "/usr/local/bin/docker-compose" + sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" + sudo mkdir -p "/usr/local/lib/docker/cli-plugins" + sudo curl -L https://github.com/docker/compose/releases/download/v2.26.0/docker-compose-`uname -s`-`uname -m` -o "/usr/local/lib/docker/cli-plugins/docker-compose" + sudo chmod +x "/usr/local/lib/docker/cli-plugins/docker-compose" + + - name: Install ${{ env.LATEST_TAG }} + run: ./install.sh + + - name: Checkout current ref + uses: actions/checkout@v4 + + - name: Install current ref + run: | + # Hacky way to get around permissioning issues in update-docker-volume-permissions.sh script + sudo -E ./install.sh + integration-test: if: github.repository_owner == 'getsentry' runs-on: ubuntu-22.04 From 23fa29d38b5d1160249b9f8011b95000b98ee8fc Mon Sep 17 00:00:00 2001 From: Alexander Tarasov Date: Mon, 6 May 2024 13:55:18 +0200 Subject: [PATCH 011/305] fix: use nginx realip module (#2977) * fix: use nginx realip module * use Docker default address pools --- nginx/nginx.conf | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 3f1e6d847fd..febbadb59bc 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -43,11 +43,24 @@ http { proxy_next_upstream error timeout invalid_header http_502 http_503 non_idempotent; proxy_next_upstream_tries 2; + # Docker default address pools + # https://github.com/moby/libnetwork/blob/3797618f9a38372e8107d8c06f6ae199e1133ae8/ipamutils/utils.go#L10-L22 + set_real_ip_from 172.17.0.0/16; + set_real_ip_from 172.18.0.0/16; + set_real_ip_from 172.19.0.0/16; + set_real_ip_from 172.20.0.0/14; + set_real_ip_from 172.24.0.0/14; + set_real_ip_from 172.28.0.0/14; + set_real_ip_from 192.168.0.0/16; + set_real_ip_from 10.0.0.0/8; + real_ip_header X-Forwarded-For; + real_ip_recursive on; + # Remove the Connection header if the client sends it, # it could be "close" to close a keepalive connection proxy_set_header Connection ''; proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-Id $request_id; proxy_read_timeout 30s; From 67382fd2abc0357e6d39634c4051cae0240da9c2 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Mon, 6 May 2024 09:22:03 -0700 Subject: [PATCH 012/305] Upgrade clickhouse to 23.8 (#3009) * upgrade clickhouse --- clickhouse/config.xml | 8 ++------ docker-compose.yml | 2 +- install.sh | 3 +++ install/detect-platform.sh | 2 -- install/upgrade-clickhouse.sh | 27 +++++++++++++++++++++++++++ 5 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 install/upgrade-clickhouse.sh diff --git a/clickhouse/config.xml b/clickhouse/config.xml index d26bfbb3850..87984468953 100644 --- a/clickhouse/config.xml +++ b/clickhouse/config.xml @@ -1,10 +1,6 @@ - - - - + + warning true diff --git a/docker-compose.yml b/docker-compose.yml index c7457b3f9eb..1c6c2ad0ebc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -217,7 +217,7 @@ services: build: context: ./clickhouse args: - BASE_IMAGE: "${CLICKHOUSE_IMAGE:-}" + BASE_IMAGE: "altinity/clickhouse-server:23.8.11.29.altinitystable" ulimits: nofile: soft: 262144 diff --git a/install.sh b/install.sh index 53c80cdeff5..f418a29fc19 100755 --- a/install.sh +++ b/install.sh @@ -20,6 +20,9 @@ source install/check-latest-commit.sh source install/check-minimum-requirements.sh # Let's go! Start impacting things. +# Upgrading clickhouse needs to come first before turning things off, since we need the old clickhouse image +# in order to determine whether or not the clickhouse version needs to be upgraded. +source install/upgrade-clickhouse.sh source install/turn-things-off.sh source install/update-docker-volume-permissions.sh source install/create-docker-volumes.sh diff --git a/install/detect-platform.sh b/install/detect-platform.sh index 32ef5ea1cdf..7404008f41c 100644 --- a/install/detect-platform.sh +++ b/install/detect-platform.sh @@ -20,10 +20,8 @@ fi export DOCKER_ARCH=$(docker info --format '{{.Architecture}}') if [[ "$DOCKER_ARCH" = "x86_64" ]]; then export DOCKER_PLATFORM="linux/amd64" - export CLICKHOUSE_IMAGE="altinity/clickhouse-server:21.8.13.1.altinitystable" elif [[ "$DOCKER_ARCH" = "aarch64" ]]; then export DOCKER_PLATFORM="linux/arm64" - export CLICKHOUSE_IMAGE="altinity/clickhouse-server:21.8.12.29.altinitydev.arm" else echo "FAIL: Unsupported docker architecture $DOCKER_ARCH." exit 1 diff --git a/install/upgrade-clickhouse.sh b/install/upgrade-clickhouse.sh new file mode 100644 index 00000000000..b0a8027b342 --- /dev/null +++ b/install/upgrade-clickhouse.sh @@ -0,0 +1,27 @@ +echo "${_group}Upgrading Clickhouse ..." + +# First check to see if user is upgrading by checking for existing clickhouse volume +if [[ -n "$(docker volume ls -q --filter name=sentry-clickhouse)" ]]; then + # Start clickhouse if it is not already running + $dc up -d clickhouse + + # Wait for clickhouse + RETRIES=30 + until $dc ps clickhouse | grep 'healthy' || [ $RETRIES -eq 0 ]; do + echo "Waiting for clickhouse server, $((RETRIES--)) remaining attempts..." + sleep 1 + done + + # In order to get to 23.8, we need to first upgrade go from 21.8 -> 22.8 -> 23.3 -> 23.8 + version=$($dc exec clickhouse clickhouse-client -q 'SELECT version()') + if [[ "$version" == "21.8.13.1.altinitystable" || "$version" == "21.8.12.29.altinitydev.arm" ]]; then + $dc down clickhouse + $dcb --build-arg BASE_IMAGE=altinity/clickhouse-server:22.8.15.25.altinitystable clickhouse + $dc up -d clickhouse + $dc down clickhouse + $dcb --build-arg BASE_IMAGE=altinity/clickhouse-server:23.3.19.33.altinitystable clickhouse + else + echo "Detected clickhouse version $version. Skipping upgrades!" + fi +fi +echo "${_endgroup}" From 1c72fbe6120444ac232df0dae242cd5af40b38df Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Mon, 6 May 2024 15:38:15 -0700 Subject: [PATCH 013/305] Add clickhouse healthchecks to upgrade (#3024) add clickhouse healthchecks --- install/upgrade-clickhouse.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/install/upgrade-clickhouse.sh b/install/upgrade-clickhouse.sh index b0a8027b342..e9472384009 100644 --- a/install/upgrade-clickhouse.sh +++ b/install/upgrade-clickhouse.sh @@ -1,16 +1,21 @@ echo "${_group}Upgrading Clickhouse ..." -# First check to see if user is upgrading by checking for existing clickhouse volume -if [[ -n "$(docker volume ls -q --filter name=sentry-clickhouse)" ]]; then - # Start clickhouse if it is not already running - $dc up -d clickhouse - +function wait_for_clickhouse() { # Wait for clickhouse RETRIES=30 until $dc ps clickhouse | grep 'healthy' || [ $RETRIES -eq 0 ]; do echo "Waiting for clickhouse server, $((RETRIES--)) remaining attempts..." sleep 1 done +} + +# First check to see if user is upgrading by checking for existing clickhouse volume +if [[ -n "$(docker volume ls -q --filter name=sentry-clickhouse)" ]]; then + # Start clickhouse if it is not already running + $dc up -d clickhouse + + # Wait for clickhouse + wait_for_clickhouse # In order to get to 23.8, we need to first upgrade go from 21.8 -> 22.8 -> 23.3 -> 23.8 version=$($dc exec clickhouse clickhouse-client -q 'SELECT version()') @@ -18,8 +23,11 @@ if [[ -n "$(docker volume ls -q --filter name=sentry-clickhouse)" ]]; then $dc down clickhouse $dcb --build-arg BASE_IMAGE=altinity/clickhouse-server:22.8.15.25.altinitystable clickhouse $dc up -d clickhouse + wait_for_clickhouse $dc down clickhouse $dcb --build-arg BASE_IMAGE=altinity/clickhouse-server:23.3.19.33.altinitystable clickhouse + $dc up -d clickhouse + wait_for_clickhouse else echo "Detected clickhouse version $version. Skipping upgrades!" fi From 40eed10dbbdce14d464d94b3871aae1f52e03be6 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 10 May 2024 14:05:19 -0700 Subject: [PATCH 014/305] remove ref to skip writes (#3041) --- docker-compose.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1c6c2ad0ebc..9c4774e2242 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -258,41 +258,41 @@ services: # Kafka consumer responsible for feeding events into Clickhouse snuba-errors-consumer: <<: *snuba_defaults - command: rust-consumer --storage errors --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage errors --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset # Kafka consumer responsible for feeding outcomes into Clickhouse # Use --auto-offset-reset=earliest to recover up to 7 days of TSDB data # since we did not do a proper migration snuba-outcomes-consumer: <<: *snuba_defaults - command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset snuba-outcomes-billing-consumer: <<: *snuba_defaults - command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write --raw-events-topic outcomes-billing + command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset --raw-events-topic outcomes-billing # Kafka consumer responsible for feeding transactions data into Clickhouse snuba-transactions-consumer: <<: *snuba_defaults - command: rust-consumer --storage transactions --consumer-group transactions_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage transactions --consumer-group transactions_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-replays-consumer: <<: *snuba_defaults - command: rust-consumer --storage replays --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage replays --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-issue-occurrence-consumer: <<: *snuba_defaults - command: rust-consumer --storage search_issues --consumer-group generic_events_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage search_issues --consumer-group generic_events_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-metrics-consumer: <<: *snuba_defaults - command: rust-consumer --storage metrics_raw --consumer-group snuba-metrics-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage metrics_raw --consumer-group snuba-metrics-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-group-attributes-consumer: <<: *snuba_defaults - command: rust-consumer --storage group_attributes --consumer-group snuba-group-attributes-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage group_attributes --consumer-group snuba-group-attributes-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-generic-metrics-distributions-consumer: <<: *snuba_defaults - command: rust-consumer --storage generic_metrics_distributions_raw --consumer-group snuba-gen-metrics-distributions-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage generic_metrics_distributions_raw --consumer-group snuba-gen-metrics-distributions-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-generic-metrics-sets-consumer: <<: *snuba_defaults - command: rust-consumer --storage generic_metrics_sets_raw --consumer-group snuba-gen-metrics-sets-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage generic_metrics_sets_raw --consumer-group snuba-gen-metrics-sets-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-generic-metrics-counters-consumer: <<: *snuba_defaults - command: rust-consumer --storage generic_metrics_counters_raw --consumer-group snuba-gen-metrics-counters-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage generic_metrics_counters_raw --consumer-group snuba-gen-metrics-counters-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-replacer: <<: *snuba_defaults command: replacer --storage errors --auto-offset-reset=latest --no-strict-offset-reset @@ -307,13 +307,13 @@ services: command: subscriptions-scheduler-executor --dataset metrics --entity metrics_sets --entity metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-metrics-subscriptions-consumers --followed-consumer-group=snuba-metrics-consumers --schedule-ttl=60 --stale-threshold-seconds=900 snuba-profiling-profiles-consumer: <<: *snuba_defaults - command: rust-consumer --storage profiles --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage profiles --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset snuba-profiling-functions-consumer: <<: *snuba_defaults - command: rust-consumer --storage functions_raw --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage functions_raw --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset snuba-spans-consumer: <<: *snuba_defaults - command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --no-skip-write + command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset symbolicator: <<: *restart_policy image: "$SYMBOLICATOR_IMAGE" From 9de4b70ece8b28d83d4b2e4a4b642ff14af52ae0 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Mon, 13 May 2024 09:50:28 -0700 Subject: [PATCH 015/305] fix: Make docker volume script respect compose project name (#3039) make the script a bit more robust in finding compose peojct name --- install/update-docker-volume-permissions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/update-docker-volume-permissions.sh b/install/update-docker-volume-permissions.sh index 463e01773e0..98cafc237d2 100644 --- a/install/update-docker-volume-permissions.sh +++ b/install/update-docker-volume-permissions.sh @@ -5,7 +5,7 @@ echo "${_group}Ensuring Kafka and Zookeeper volumes have correct permissions ... if [[ "$DOCKER_PLATFORM" = "linux/amd64" && -n "$(docker volume ls -q -f name=sentry-zookeeper)" && -n "$(docker volume ls -q -f name=sentry-kafka)" ]]; then zookeeper_data_dir="/var/lib/docker/volumes/sentry-zookeeper/_data" kafka_data_dir="/var/lib/docker/volumes/sentry-kafka/_data" - zookeeper_log_data_dir="/var/lib/docker/volumes/sentry-self-hosted_sentry-zookeeper-log/_data" + zookeeper_log_data_dir="/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}_sentry-zookeeper-log/_data" chmod -R a+w $zookeeper_data_dir $kafka_data_dir $zookeeper_log_data_dir && returncode=$? || returncode=$? if [[ $returncode == "1" ]]; then echo "WARNING: Error when setting appropriate permissions for zookeeper, kafka, and zookeeper log docker volumes. This may corrupt your self-hosted install. See https://github.com/confluentinc/kafka-images/issues/127 for context on why this was added." From 2b26c7ca78e4721cd74bc62f03093d77f421c7ee Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 16 May 2024 18:51:31 +0000 Subject: [PATCH 016/305] release: 24.5.0 --- .env | 10 +++++----- CHANGELOG.md | 12 ++++++++++++ README.md | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 8e54a3df2c9..c43fada1445 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.5.0 +SNUBA_IMAGE=getsentry/snuba:24.5.0 +RELAY_IMAGE=getsentry/relay:24.5.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.5.0 +VROOM_IMAGE=getsentry/vroom:24.5.0 WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/CHANGELOG.md b/CHANGELOG.md index 735a055ac5a..ceab2dc54d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 24.5.0 + +### Various fixes & improvements + +- fix: Make docker volume script respect compose project name (#3039) by @hubertdeng123 +- remove ref to skip writes (#3041) by @john-z-yang +- Add clickhouse healthchecks to upgrade (#3024) by @hubertdeng123 +- Upgrade clickhouse to 23.8 (#3009) by @hubertdeng123 +- fix: use nginx realip module (#2977) by @oioki +- Add upgrade test (#3012) by @hubertdeng123 +- Bump kafka and zookeeper versions (#2988) by @hubertdeng123 + ## 24.4.2 ### Various fixes & improvements diff --git a/README.md b/README.md index 13f4f2b8934..74d84ae21c6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry nightly +# Self-Hosted Sentry 24.5.0 Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From f22bc2acf546d3732ce896a6f87ad7d379ba6b1f Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 16 May 2024 19:23:21 +0000 Subject: [PATCH 017/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index c43fada1445..8e54a3df2c9 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.5.0 -SNUBA_IMAGE=getsentry/snuba:24.5.0 -RELAY_IMAGE=getsentry/relay:24.5.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.5.0 -VROOM_IMAGE=getsentry/vroom:24.5.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/README.md b/README.md index 74d84ae21c6..13f4f2b8934 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry 24.5.0 +# Self-Hosted Sentry nightly Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From 9afc35910e66d80855815be0309b9e8fc1aa2974 Mon Sep 17 00:00:00 2001 From: Vova Luchaninov Date: Tue, 21 May 2024 19:30:11 +0200 Subject: [PATCH 018/305] Typo in config.example.yml (#3063) Update config.example.yml typo --- sentry/config.example.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/config.example.yml b/sentry/config.example.yml index 10f5c8c16f7..de0b68b99f8 100644 --- a/sentry/config.example.yml +++ b/sentry/config.example.yml @@ -117,7 +117,7 @@ transaction-events.force-disable-internal-project: true # slack.client-id: <'client id'> # slack.client-secret: # slack.signing-secret: -## If legacy-app is True use verfication-token instead of signing-secret +## If legacy-app is True use verification-token instead of signing-secret # slack.verification-token: From 6032d980254bafc8858acd53ede53669747f9d00 Mon Sep 17 00:00:00 2001 From: Nicolas Boutet Date: Wed, 22 May 2024 04:14:52 +0200 Subject: [PATCH 019/305] Fix install: use dynamic docker root dir instead of hardcoded one (#3064) Fix: use dynamic docker root dir instead of hardcoded --- install/update-docker-volume-permissions.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/install/update-docker-volume-permissions.sh b/install/update-docker-volume-permissions.sh index 98cafc237d2..5dbc04f69f0 100644 --- a/install/update-docker-volume-permissions.sh +++ b/install/update-docker-volume-permissions.sh @@ -3,9 +3,10 @@ echo "${_group}Ensuring Kafka and Zookeeper volumes have correct permissions ... # Only supporting platforms on linux x86 platforms and not apple silicon. I'm assuming that folks using apple silicon are doing it for dev purposes and it's difficult # to change permissions of docker volumes since it is run in a VM. if [[ "$DOCKER_PLATFORM" = "linux/amd64" && -n "$(docker volume ls -q -f name=sentry-zookeeper)" && -n "$(docker volume ls -q -f name=sentry-kafka)" ]]; then - zookeeper_data_dir="/var/lib/docker/volumes/sentry-zookeeper/_data" - kafka_data_dir="/var/lib/docker/volumes/sentry-kafka/_data" - zookeeper_log_data_dir="/var/lib/docker/volumes/${COMPOSE_PROJECT_NAME}_sentry-zookeeper-log/_data" + docker_root_dir=$(docker info --format '{{.DockerRootDir}}') + zookeeper_data_dir="${docker_root_dir}/volumes/sentry-zookeeper/_data" + kafka_data_dir="${docker_root_dir}/volumes/sentry-kafka/_data" + zookeeper_log_data_dir="${docker_root_dir}/volumes/${COMPOSE_PROJECT_NAME}_sentry-zookeeper-log/_data" chmod -R a+w $zookeeper_data_dir $kafka_data_dir $zookeeper_log_data_dir && returncode=$? || returncode=$? if [[ $returncode == "1" ]]; then echo "WARNING: Error when setting appropriate permissions for zookeeper, kafka, and zookeeper log docker volumes. This may corrupt your self-hosted install. See https://github.com/confluentinc/kafka-images/issues/127 for context on why this was added." From 6917e398bb603e1673b2e2dc7ca2ccbb466305c7 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Tue, 28 May 2024 13:47:01 -0700 Subject: [PATCH 020/305] chore: Add comment explaining the one liner in clickhouse config (#3085) add comment explaining the one liner in clickhouse config --- clickhouse/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clickhouse/config.xml b/clickhouse/config.xml index 87984468953..19a0ecf80a9 100644 --- a/clickhouse/config.xml +++ b/clickhouse/config.xml @@ -1,5 +1,5 @@ - + warning From ede1e6f83613f1506e656f8015c844f889ca574a Mon Sep 17 00:00:00 2001 From: Pierre Massat Date: Wed, 29 May 2024 13:32:30 -0400 Subject: [PATCH 021/305] ref(spans): Add new feature flags needed (#3092) * ref(spans): Add new feature flags needed * Add new UI flags * Remove addons ingest flag as we're not releasing addons yet * Remove obsolete flags --- sentry/sentry.conf.example.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 40e2728569f..5213d1e06af 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -294,21 +294,22 @@ def get_internal_network(): "projects:servicehooks", ) + ( - "projects:span-metrics-extraction", + "organizations:deprecate-fid-from-performance-score", + "organizations:indexed-spans-extraction", + "organizations:insights-entry-points", + "organizations:insights-initial-modules", + "organizations:mobile-ttid-ttfd-contribution", + "organizations:performance-calculate-score-relay", + "organizations:spans-first-ui", + "organizations:standalone-span-ingestion", "organizations:starfish-browser-resource-module-image-view", "organizations:starfish-browser-resource-module-ui", "organizations:starfish-browser-webvitals", "organizations:starfish-browser-webvitals-pageoverview-v2", - "organizations:starfish-browser-webvitals-use-backend-scores", - "organizations:performance-calculate-score-relay", "organizations:starfish-browser-webvitals-replace-fid-with-inp", - "organizations:deprecate-fid-from-performance-score", - "organizations:performance-database-view", - "organizations:performance-screens-view", - "organizations:mobile-ttid-ttfd-contribution", + "organizations:starfish-browser-webvitals-use-backend-scores", "organizations:starfish-mobile-appstart", - "organizations:standalone-span-ingestion", - "organizations:spans-first-ui", + "projects:span-metrics-extraction", ) # starfish related flags } ) From 0dabb5a4cc6dabc3e238db60c5d1afca4afcea41 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Wed, 29 May 2024 11:30:44 -0700 Subject: [PATCH 022/305] Different approach to editing permissions of docker volumes (#3084) * different approach to editing permissions of docker volumes --- .github/workflows/test.yml | 4 +--- install/update-docker-volume-permissions.sh | 11 ++--------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e2303cd97d3..8acdb988133 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,9 +73,7 @@ jobs: uses: actions/checkout@v4 - name: Install current ref - run: | - # Hacky way to get around permissioning issues in update-docker-volume-permissions.sh script - sudo -E ./install.sh + run: ./install.sh integration-test: if: github.repository_owner == 'getsentry' diff --git a/install/update-docker-volume-permissions.sh b/install/update-docker-volume-permissions.sh index 5dbc04f69f0..8ac0be400c4 100644 --- a/install/update-docker-volume-permissions.sh +++ b/install/update-docker-volume-permissions.sh @@ -2,15 +2,8 @@ echo "${_group}Ensuring Kafka and Zookeeper volumes have correct permissions ... # Only supporting platforms on linux x86 platforms and not apple silicon. I'm assuming that folks using apple silicon are doing it for dev purposes and it's difficult # to change permissions of docker volumes since it is run in a VM. -if [[ "$DOCKER_PLATFORM" = "linux/amd64" && -n "$(docker volume ls -q -f name=sentry-zookeeper)" && -n "$(docker volume ls -q -f name=sentry-kafka)" ]]; then - docker_root_dir=$(docker info --format '{{.DockerRootDir}}') - zookeeper_data_dir="${docker_root_dir}/volumes/sentry-zookeeper/_data" - kafka_data_dir="${docker_root_dir}/volumes/sentry-kafka/_data" - zookeeper_log_data_dir="${docker_root_dir}/volumes/${COMPOSE_PROJECT_NAME}_sentry-zookeeper-log/_data" - chmod -R a+w $zookeeper_data_dir $kafka_data_dir $zookeeper_log_data_dir && returncode=$? || returncode=$? - if [[ $returncode == "1" ]]; then - echo "WARNING: Error when setting appropriate permissions for zookeeper, kafka, and zookeeper log docker volumes. This may corrupt your self-hosted install. See https://github.com/confluentinc/kafka-images/issues/127 for context on why this was added." - fi +if [[ -n "$(docker volume ls -q -f name=sentry-zookeeper)" && -n "$(docker volume ls -q -f name=sentry-kafka)" ]]; then + docker run --rm -v "sentry-zookeeper:/sentry-zookeeper-data" -v "sentry-kafka:/sentry-kafka-data" -v "${COMPOSE_PROJECT_NAME}_sentry-zookeeper-log:/sentry-zookeeper-log-data" busybox chmod -R a+w /sentry-zookeeper-data /sentry-kafka-data /sentry-zookeeper-log-data fi echo "${_endgroup}" From c40b1530d104e9481d172e06dc6810bea0795d5c Mon Sep 17 00:00:00 2001 From: Jann Kleen Date: Wed, 29 May 2024 23:59:22 +0200 Subject: [PATCH 023/305] Update minimum docker compose requirement (#3078) * Update minimum docker compose requirement docker compose down is now required. * Update docker compose version to new minimum in CI config. --- .github/workflows/test.yml | 6 +++--- README.md | 2 +- install/_min-requirements.sh | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8acdb988133..e565392c897 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,9 +83,9 @@ jobs: fail-fast: false matrix: customizations: ["disabled", "enabled"] - compose_version: ["v2.0.1", "v2.26.0"] + compose_version: ["v2.19.0", "v2.26.0"] include: - - compose_version: "v2.0.1" + - compose_version: "v2.19.0" compose_path: "/usr/local/lib/docker/cli-plugins" - compose_version: "v2.26.0" compose_path: "/usr/local/lib/docker/cli-plugins" @@ -134,7 +134,7 @@ jobs: - name: Integration Test run: | - if [ "${{ matrix.compose_version }}" = "v2.0.1" ]; then + if [ "${{ matrix.compose_version }}" = "v2.19.0" ]; then pytest --reruns 3 --cov --junitxml=junit.xml _integration-test/ --customizations=${{ matrix.customizations }} else pytest --cov --junitxml=junit.xml _integration-test/ --customizations=${{ matrix.customizations }} diff --git a/README.md b/README.md index 13f4f2b8934..7315466c250 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docke ## Requirements * Docker 19.03.6+ -* Compose 2.0.1+ +* Compose 2.19.0+ * 4 CPU Cores * 16 GB RAM * 20 GB Free Disk Space diff --git a/install/_min-requirements.sh b/install/_min-requirements.sh index e756c765d80..f8836db0863 100644 --- a/install/_min-requirements.sh +++ b/install/_min-requirements.sh @@ -1,6 +1,6 @@ # Don't forget to update the README and othes docs when you change these! MIN_DOCKER_VERSION='19.03.6' -MIN_COMPOSE_VERSION='2.0.1' +MIN_COMPOSE_VERSION='2.19.0' MIN_RAM_HARD=3800 # MB MIN_RAM_SOFT=7800 # MB MIN_CPU_HARD=2 From f8e95ec8686f23a4ed14d413599d3169e5beb165 Mon Sep 17 00:00:00 2001 From: Dan Fuller Date: Tue, 4 Jun 2024 10:35:30 -0700 Subject: [PATCH 024/305] feat: Add crons task consumers (#3106) We now process tasks via Kafka consumers instead of celerybeat. This needs to be added to self-hosted as well --- docker-compose.yml | 6 ++++++ install/create-kafka-topics.sh | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 9c4774e2242..84fb56da793 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -384,6 +384,12 @@ services: ingest-monitors: <<: *sentry_defaults command: run consumer --no-strict-offset-reset ingest-monitors --consumer-group ingest-monitors + monitors-clock-tick: + <<: *sentry_defaults + command: run consumer --no-strict-offset-reset monitors-clock-tick --consumer-group monitors-clock-tick + monitors-clock-tasks: + <<: *sentry_defaults + command: run consumer --no-strict-offset-reset monitors-clock-tasks --consumer-group monitors-clock-tasks post-process-forwarder-errors: <<: *sentry_defaults command: run consumer post-process-forwarder-errors --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-commit-log --synchronize-commit-group=snuba-consumers diff --git a/install/create-kafka-topics.sh b/install/create-kafka-topics.sh index 63e0cffa016..ff2ba8e6608 100644 --- a/install/create-kafka-topics.sh +++ b/install/create-kafka-topics.sh @@ -14,7 +14,7 @@ done # XXX(BYK): We cannot use auto.create.topics as Confluence and Apache hates it now (and makes it very hard to enable) EXISTING_KAFKA_TOPICS=$($dc exec -T kafka kafka-topics --list --bootstrap-server kafka:9092 2>/dev/null) -NEEDED_KAFKA_TOPICS="ingest-attachments ingest-transactions ingest-events ingest-replay-recordings profiles ingest-occurrences ingest-metrics ingest-performance-metrics ingest-monitors" +NEEDED_KAFKA_TOPICS="ingest-attachments ingest-transactions ingest-events ingest-replay-recordings profiles ingest-occurrences ingest-metrics ingest-performance-metrics ingest-monitors monitors-clock-tasks" for topic in $NEEDED_KAFKA_TOPICS; do if ! echo "$EXISTING_KAFKA_TOPICS" | grep -qE "(^| )$topic( |$)"; then $dc exec kafka kafka-topics --create --topic $topic --bootstrap-server kafka:9092 @@ -22,4 +22,11 @@ for topic in $NEEDED_KAFKA_TOPICS; do fi done +# This topic must have only a single partition for the consumer to work correctly +# https://github.com/getsentry/ops/blob/7dbc26f39c584ec924c8fef2ad5c532d6a158be3/k8s/clusters/us/_topicctl.yaml#L288-L295 + +if ! echo "$EXISTING_KAFKA_TOPICS" | grep -qE "(^| )monitors-clock-tick( |$)"; then + $dc exec kafka kafka-topics --create --topic monitors-clock-tick --bootstrap-server kafka:9092 --partitions 1 +fi + echo "${_endgroup}" From 3455a33a4ce1f2e80c25adb64d8845f45ae62196 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Tue, 4 Jun 2024 12:07:35 -0700 Subject: [PATCH 025/305] Update consumer flags (#3112) update consumer flags --- docker-compose.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 84fb56da793..61d87ae32ef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -380,25 +380,25 @@ services: command: run consumer ingest-occurrences --consumer-group ingest-occurrences ingest-profiles: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset ingest-profiles --consumer-group ingest-profiles + command: run consumer ingest-profiles --consumer-group ingest-profiles ingest-monitors: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset ingest-monitors --consumer-group ingest-monitors + command: run consumer ingest-monitors --consumer-group ingest-monitors monitors-clock-tick: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset monitors-clock-tick --consumer-group monitors-clock-tick + command: run consumer monitors-clock-tick --consumer-group monitors-clock-tick monitors-clock-tasks: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset monitors-clock-tasks --consumer-group monitors-clock-tasks + command: run consumer monitors-clock-tasks --consumer-group monitors-clock-tasks post-process-forwarder-errors: <<: *sentry_defaults - command: run consumer post-process-forwarder-errors --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-commit-log --synchronize-commit-group=snuba-consumers + command: run consumer --no-strict-offset-reset post-process-forwarder-errors --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-commit-log --synchronize-commit-group=snuba-consumers post-process-forwarder-transactions: <<: *sentry_defaults - command: run consumer post-process-forwarder-transactions --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-transactions-commit-log --synchronize-commit-group transactions_group + command: run consumer --no-strict-offset-reset post-process-forwarder-transactions --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-transactions-commit-log --synchronize-commit-group transactions_group post-process-forwarder-issue-platform: <<: *sentry_defaults - command: run consumer post-process-forwarder-issue-platform --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-generic-events-commit-log --synchronize-commit-group generic_events_group + command: run consumer --no-strict-offset-reset post-process-forwarder-issue-platform --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-generic-events-commit-log --synchronize-commit-group generic_events_group subscription-consumer-events: <<: *sentry_defaults command: run consumer events-subscription-results --consumer-group query-subscription-consumer From 601897160706c8544d09420a231593c47eb73487 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 4 Jun 2024 21:37:10 +0000 Subject: [PATCH 026/305] release: 24.5.1 --- .env | 10 +++++----- CHANGELOG.md | 13 +++++++++++++ README.md | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 8e54a3df2c9..a8dcb6c9252 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.5.1 +SNUBA_IMAGE=getsentry/snuba:24.5.1 +RELAY_IMAGE=getsentry/relay:24.5.1 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.5.1 +VROOM_IMAGE=getsentry/vroom:24.5.1 WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/CHANGELOG.md b/CHANGELOG.md index ceab2dc54d1..59b9aeb2595 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 24.5.1 + +### Various fixes & improvements + +- Update consumer flags (#3112) by @hubertdeng123 +- feat: Add crons task consumers (#3106) by @wedamija +- Update minimum docker compose requirement (#3078) by @JannKleen +- Different approach to editing permissions of docker volumes (#3084) by @hubertdeng123 +- ref(spans): Add new feature flags needed (#3092) by @phacops +- chore: Add comment explaining the one liner in clickhouse config (#3085) by @hubertdeng123 +- Fix install: use dynamic docker root dir instead of hardcoded one (#3064) by @boutetnico +- Typo in config.example.yml (#3063) by @luchaninov + ## 24.5.0 ### Various fixes & improvements diff --git a/README.md b/README.md index 7315466c250..3dddde17a91 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry nightly +# Self-Hosted Sentry 24.5.1 Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From b819d95c169192ac606b086cfd4fc534055091df Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 4 Jun 2024 22:00:05 +0000 Subject: [PATCH 027/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index a8dcb6c9252..8e54a3df2c9 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.5.1 -SNUBA_IMAGE=getsentry/snuba:24.5.1 -RELAY_IMAGE=getsentry/relay:24.5.1 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.5.1 -VROOM_IMAGE=getsentry/vroom:24.5.1 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/README.md b/README.md index 3dddde17a91..7315466c250 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry 24.5.1 +# Self-Hosted Sentry nightly Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From e8146adafd2a3d5a206c6d70633f4277d1c6cf1b Mon Sep 17 00:00:00 2001 From: Ivana Kellyerova Date: Wed, 5 Jun 2024 20:42:47 +0200 Subject: [PATCH 028/305] Bump Python SDK version used in tests (#3108) Bump Python SDK version in tests --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 7ef178da75a..42bf67b2472 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,4 @@ -sentry-sdk>=1.39.2 +sentry-sdk>=2.4.0 pytest>=8.0.0 pytest-cov>=4.1.0 pytest-rerunfailures>=11.0 From 419d6ccf4e4d0dde2db301e43370d019f9a4c69b Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Fri, 7 Jun 2024 09:49:58 -0700 Subject: [PATCH 029/305] Use non-alpine postgres (#3116) use non-alpine postgres --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 61d87ae32ef..f88d74d99e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -132,7 +132,7 @@ services: postgres: <<: *restart_policy # Using the same postgres version as Sentry dev for consistency purposes - image: "postgres:14.11-alpine" + image: "postgres:14.11" healthcheck: <<: *healthcheck_defaults # Using default user "postgres" from sentry/sentry.conf.example.py or value of POSTGRES_USER if provided From a6cb07691018bbe66360208b5f5f507f64b3f606 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Wed, 12 Jun 2024 15:37:15 -0700 Subject: [PATCH 030/305] Use general kafka topic creation in self-hosted (#3121) * use general kafka topic creation --- install.sh | 1 - install/create-kafka-topics.sh | 32 -------------------------- install/set-up-and-migrate-database.sh | 4 ++-- 3 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 install/create-kafka-topics.sh diff --git a/install.sh b/install.sh index f418a29fc19..ac5a2f0f4b2 100755 --- a/install.sh +++ b/install.sh @@ -34,7 +34,6 @@ source install/update-docker-images.sh source install/build-docker-images.sh source install/install-wal2json.sh source install/bootstrap-snuba.sh -source install/create-kafka-topics.sh source install/upgrade-postgres.sh source install/set-up-and-migrate-database.sh source install/geoip.sh diff --git a/install/create-kafka-topics.sh b/install/create-kafka-topics.sh deleted file mode 100644 index ff2ba8e6608..00000000000 --- a/install/create-kafka-topics.sh +++ /dev/null @@ -1,32 +0,0 @@ -echo "${_group}Creating additional Kafka topics ..." - -$dc up -d --no-build --no-recreate kafka - -while [ true ]; do - kafka_healthy=$($dc ps kafka | grep 'healthy') - if [ ! -z "$kafka_healthy" ]; then - break - fi - - echo "Kafka container is not healthy, waiting for 30 seconds. If this took too long, abort the installation process, and check your Kafka configuration" - sleep 30s -done - -# XXX(BYK): We cannot use auto.create.topics as Confluence and Apache hates it now (and makes it very hard to enable) -EXISTING_KAFKA_TOPICS=$($dc exec -T kafka kafka-topics --list --bootstrap-server kafka:9092 2>/dev/null) -NEEDED_KAFKA_TOPICS="ingest-attachments ingest-transactions ingest-events ingest-replay-recordings profiles ingest-occurrences ingest-metrics ingest-performance-metrics ingest-monitors monitors-clock-tasks" -for topic in $NEEDED_KAFKA_TOPICS; do - if ! echo "$EXISTING_KAFKA_TOPICS" | grep -qE "(^| )$topic( |$)"; then - $dc exec kafka kafka-topics --create --topic $topic --bootstrap-server kafka:9092 - echo "" - fi -done - -# This topic must have only a single partition for the consumer to work correctly -# https://github.com/getsentry/ops/blob/7dbc26f39c584ec924c8fef2ad5c532d6a158be3/k8s/clusters/us/_topicctl.yaml#L288-L295 - -if ! echo "$EXISTING_KAFKA_TOPICS" | grep -qE "(^| )monitors-clock-tick( |$)"; then - $dc exec kafka kafka-topics --create --topic monitors-clock-tick --bootstrap-server kafka:9092 --partitions 1 -fi - -echo "${_endgroup}" diff --git a/install/set-up-and-migrate-database.sh b/install/set-up-and-migrate-database.sh index 6880622ae6c..09c87dc8450 100644 --- a/install/set-up-and-migrate-database.sh +++ b/install/set-up-and-migrate-database.sh @@ -19,7 +19,7 @@ with connection.cursor() as cursor: " if [[ -n "${CI:-}" || "${SKIP_USER_CREATION:-0}" == 1 ]]; then - $dcr web upgrade --noinput + $dcr web upgrade --noinput --create-kafka-topics echo "" echo "Did not prompt for user creation. Run the following command to create one" echo "yourself (recommended):" @@ -27,7 +27,7 @@ if [[ -n "${CI:-}" || "${SKIP_USER_CREATION:-0}" == 1 ]]; then echo " $dc_base run --rm web createuser" echo "" else - $dcr web upgrade + $dcr web upgrade --create-kafka-topics fi echo "${_endgroup}" From 7ec463082bdc957470a98bffb2f1b685d5aba36c Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sat, 15 Jun 2024 18:05:28 +0000 Subject: [PATCH 031/305] release: 24.6.0 --- .env | 10 +++++----- CHANGELOG.md | 8 ++++++++ README.md | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 8e54a3df2c9..c718928d762 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.6.0 +SNUBA_IMAGE=getsentry/snuba:24.6.0 +RELAY_IMAGE=getsentry/relay:24.6.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.6.0 +VROOM_IMAGE=getsentry/vroom:24.6.0 WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/CHANGELOG.md b/CHANGELOG.md index 59b9aeb2595..2d077215e49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 24.6.0 + +### Various fixes & improvements + +- Use general kafka topic creation in self-hosted (#3121) by @hubertdeng123 +- Use non-alpine postgres (#3116) by @hubertdeng123 +- Bump Python SDK version used in tests (#3108) by @sentrivana + ## 24.5.1 ### Various fixes & improvements diff --git a/README.md b/README.md index 7315466c250..b8ccfeced36 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry nightly +# Self-Hosted Sentry 24.6.0 Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From 05fa62a0c3029216cdf6a7c391df0fbca3070a7a Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 18 Jun 2024 19:34:29 +0000 Subject: [PATCH 032/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index c718928d762..8e54a3df2c9 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.6.0 -SNUBA_IMAGE=getsentry/snuba:24.6.0 -RELAY_IMAGE=getsentry/relay:24.6.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.6.0 -VROOM_IMAGE=getsentry/vroom:24.6.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/README.md b/README.md index b8ccfeced36..7315466c250 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry 24.6.0 +# Self-Hosted Sentry nightly Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From da06c0f230454b91fada3980ba2e1e012cedf1d2 Mon Sep 17 00:00:00 2001 From: Riccardo Busetti Date: Thu, 20 Jun 2024 14:56:57 +0200 Subject: [PATCH 033/305] feat(relay): Forward /api/0/relays/* to inner relays (#3144) --- nginx/nginx.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nginx/nginx.conf b/nginx/nginx.conf index febbadb59bc..c24fe7ec188 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -85,6 +85,9 @@ http { location ~ ^/api/[1-9]\d*/ { proxy_pass http://relay; } + location ^~ /api/0/relays/ { + proxy_pass http://relay; + } location / { proxy_pass http://sentry; } From e39ac04ccc278606284cdac66e1e5fe0453b57a3 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 9 Jul 2024 07:37:50 +0700 Subject: [PATCH 034/305] feat: add insights feature flags (#3152) * feat: add insights feature flags * feat: add span metrics extractions addons feature flag --- sentry/sentry.conf.example.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 5213d1e06af..38a461f46cb 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -298,9 +298,9 @@ def get_internal_network(): "organizations:indexed-spans-extraction", "organizations:insights-entry-points", "organizations:insights-initial-modules", + "organizations:insights-addon-modules", "organizations:mobile-ttid-ttfd-contribution", "organizations:performance-calculate-score-relay", - "organizations:spans-first-ui", "organizations:standalone-span-ingestion", "organizations:starfish-browser-resource-module-image-view", "organizations:starfish-browser-resource-module-ui", @@ -310,6 +310,7 @@ def get_internal_network(): "organizations:starfish-browser-webvitals-use-backend-scores", "organizations:starfish-mobile-appstart", "projects:span-metrics-extraction", + "projects:span-metrics-extraction-addons", ) # starfish related flags } ) From 65779a77a535e57c1034c04b8de49f1363ac35a2 Mon Sep 17 00:00:00 2001 From: Christoph Keller Date: Tue, 9 Jul 2024 21:09:01 +0200 Subject: [PATCH 035/305] Update sentry-admin.sh to select its own working directory (#3184) `sentry-admin.sh` only works when called from the working directory and not using its absolute path. This change makes it also callable using its absolute path. --- sentry-admin.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sentry-admin.sh b/sentry-admin.sh index 85705516d27..d162c82114d 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -1,5 +1,8 @@ #!/bin/bash +# Set the script directory as working directory. +cd $(dirname $0) + # Detect docker and platform state. source install/dc-detect-version.sh source install/detect-platform.sh From c18da05a4641a1c0c45eb51486b7418ab3c20376 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Fri, 12 Jul 2024 09:33:49 -0700 Subject: [PATCH 036/305] Check postgres os before proceeding with install (#3197) * check postgres os before proceeding * use dc --- install/set-up-and-migrate-database.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/install/set-up-and-migrate-database.sh b/install/set-up-and-migrate-database.sh index 09c87dc8450..7bf74f40e95 100644 --- a/install/set-up-and-migrate-database.sh +++ b/install/set-up-and-migrate-database.sh @@ -9,6 +9,12 @@ until $dc exec postgres psql -U postgres -c "select 1" >/dev/null 2>&1 || [ $RET sleep 1 done +os=$($dc exec postgres cat /etc/os-release | grep 'ID=debian') +if [[ -z $os ]]; then + echo "Postgres image debian check failed, exiting..." + exit 1 +fi + # Using django ORM to provide broader support for users with external databases $dcr web shell -c " from django.db import connection From 8936d2a27e3226bf609a76dbd0f0722786badef6 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 15 Jul 2024 18:05:40 +0000 Subject: [PATCH 037/305] release: 24.7.0 --- .env | 10 +++++----- CHANGELOG.md | 9 +++++++++ README.md | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 8e54a3df2c9..029fa6f13f2 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.7.0 +SNUBA_IMAGE=getsentry/snuba:24.7.0 +RELAY_IMAGE=getsentry/relay:24.7.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.7.0 +VROOM_IMAGE=getsentry/vroom:24.7.0 WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d077215e49..9490a34b78f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 24.7.0 + +### Various fixes & improvements + +- Check postgres os before proceeding with install (#3197) by @hubertdeng123 +- Update sentry-admin.sh to select its own working directory (#3184) by @theoriginalgri +- feat: add insights feature flags (#3152) by @aldy505 +- feat(relay): Forward /api/0/relays/* to inner relays (#3144) by @iambriccardo + ## 24.6.0 ### Various fixes & improvements diff --git a/README.md b/README.md index 7315466c250..b5d626f6b6d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry nightly +# Self-Hosted Sentry 24.7.0 Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From f04ee1a11a1efa69774495da6bda7d15e9a4395a Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 15 Jul 2024 23:39:34 +0000 Subject: [PATCH 038/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 029fa6f13f2..8e54a3df2c9 100644 --- a/.env +++ b/.env @@ -5,11 +5,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.7.0 -SNUBA_IMAGE=getsentry/snuba:24.7.0 -RELAY_IMAGE=getsentry/relay:24.7.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.7.0 -VROOM_IMAGE=getsentry/vroom:24.7.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/README.md b/README.md index b5d626f6b6d..7315466c250 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry 24.7.0 +# Self-Hosted Sentry nightly Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From ca5f35c94f33d50be04c35bcb4c16cc705538df2 Mon Sep 17 00:00:00 2001 From: Riya Chakraborty <47572810+ayirr7@users.noreply.github.com> Date: Tue, 16 Jul 2024 09:59:57 -0700 Subject: [PATCH 039/305] feat(generic-metrics): Add gauges to docker compose, re-try (#3177) * add gauges * use rust consumer instead --- docker-compose.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f88d74d99e7..e524d0fd0e8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -177,8 +177,7 @@ services: - "sentry-secrets:/etc/zookeeper/secrets" healthcheck: <<: *healthcheck_defaults - test: - ["CMD-SHELL", 'echo "ruok" | nc -w 2 localhost 2181 | grep imok'] + test: ["CMD-SHELL", 'echo "ruok" | nc -w 2 localhost 2181 | grep imok'] kafka: <<: *restart_policy depends_on: @@ -250,7 +249,8 @@ services: # Override the entrypoint in order to avoid using envvars for config. # Futz with settings so we can keep mmdb and conf in same dir on host # (image looks for them in separate dirs by default). - entrypoint: ["/usr/bin/geoipupdate", "-d", "/sentry", "-f", "/sentry/GeoIP.conf"] + entrypoint: + ["/usr/bin/geoipupdate", "-d", "/sentry", "-f", "/sentry/GeoIP.conf"] volumes: - "./geoip:/sentry" snuba-api: @@ -293,6 +293,9 @@ services: snuba-generic-metrics-counters-consumer: <<: *snuba_defaults command: rust-consumer --storage generic_metrics_counters_raw --consumer-group snuba-gen-metrics-counters-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-generic-metrics-gauges-consumer: + <<: *snuba_defaults + command: rust-consumer --storage generic_metrics_gauges_raw --consumer-group snuba-gen-metrics-gauges-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset snuba-replacer: <<: *snuba_defaults command: replacer --storage errors --auto-offset-reset=latest --no-strict-offset-reset From 485d3ffd2f6e6bc5b64afb0721ac2e75ed5ee33a Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Mon, 22 Jul 2024 10:23:05 -0700 Subject: [PATCH 040/305] Add errors only self-hosted infrastructure (#3190) --- .env | 1 + docker-compose.yml | 123 ++++++++++++++++++++++++---------- sentry/sentry.conf.example.py | 3 + 3 files changed, 91 insertions(+), 36 deletions(-) diff --git a/.env b/.env index 8e54a3df2c9..430cdac1d5d 100644 --- a/.env +++ b/.env @@ -1,4 +1,5 @@ COMPOSE_PROJECT_NAME=sentry-self-hosted +COMPOSE_PROFILES=feature-complete SENTRY_EVENT_RETENTION_DAYS=90 # You can either use a port number or an IP:PORT combo for SENTRY_BIND # See https://docs.docker.com/compose/compose-file/#ports for more diff --git a/docker-compose.yml b/docker-compose.yml index e524d0fd0e8..af7aab1d2de 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,24 +36,8 @@ x-sentry-defaults: &sentry_defaults <<: *depends_on-default snuba-api: <<: *depends_on-default - snuba-errors-consumer: - <<: *depends_on-default - snuba-outcomes-consumer: - <<: *depends_on-default - snuba-outcomes-billing-consumer: - <<: *depends_on-default - snuba-transactions-consumer: - <<: *depends_on-default - snuba-subscription-consumer-events: - <<: *depends_on-default - snuba-subscription-consumer-transactions: - <<: *depends_on-default - snuba-replacer: - <<: *depends_on-default symbolicator: <<: *depends_on-default - vroom: - <<: *depends_on-default entrypoint: "/etc/sentry/entrypoint.sh" command: ["run", "web"] environment: @@ -71,6 +55,7 @@ x-sentry-defaults: &sentry_defaults GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR: *ca_bundle # Leaving the value empty to just pass whatever is set # on the host system (or in the .env file) + COMPOSE_PROFILES: SENTRY_EVENT_RETENTION_DAYS: SENTRY_MAIL_HOST: SENTRY_MAX_EXTERNAL_SOURCEMAP_SIZE: @@ -268,55 +253,84 @@ services: snuba-outcomes-billing-consumer: <<: *snuba_defaults command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset --raw-events-topic outcomes-billing + snuba-group-attributes-consumer: + <<: *snuba_defaults + command: rust-consumer --storage group_attributes --consumer-group snuba-group-attributes-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-replacer: + <<: *snuba_defaults + command: replacer --storage errors --auto-offset-reset=latest --no-strict-offset-reset + snuba-subscription-consumer-events: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset events --entity events --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-events-subscriptions-consumers --followed-consumer-group=snuba-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + ############################################# + ## Feature Complete Sentry Snuba Consumers ## + ############################################# # Kafka consumer responsible for feeding transactions data into Clickhouse snuba-transactions-consumer: <<: *snuba_defaults command: rust-consumer --storage transactions --consumer-group transactions_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + profiles: + - feature-complete snuba-replays-consumer: <<: *snuba_defaults command: rust-consumer --storage replays --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + profiles: + - feature-complete snuba-issue-occurrence-consumer: <<: *snuba_defaults command: rust-consumer --storage search_issues --consumer-group generic_events_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + profiles: + - feature-complete snuba-metrics-consumer: <<: *snuba_defaults command: rust-consumer --storage metrics_raw --consumer-group snuba-metrics-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset - snuba-group-attributes-consumer: + profiles: + - feature-complete + snuba-subscription-consumer-transactions: <<: *snuba_defaults - command: rust-consumer --storage group_attributes --consumer-group snuba-group-attributes-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: subscriptions-scheduler-executor --dataset transactions --entity transactions --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-transactions-subscriptions-consumers --followed-consumer-group=transactions_group --schedule-ttl=60 --stale-threshold-seconds=900 + profiles: + - feature-complete + snuba-subscription-consumer-metrics: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset metrics --entity metrics_sets --entity metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-metrics-subscriptions-consumers --followed-consumer-group=snuba-metrics-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + profiles: + - feature-complete snuba-generic-metrics-distributions-consumer: <<: *snuba_defaults command: rust-consumer --storage generic_metrics_distributions_raw --consumer-group snuba-gen-metrics-distributions-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + profiles: + - feature-complete snuba-generic-metrics-sets-consumer: <<: *snuba_defaults command: rust-consumer --storage generic_metrics_sets_raw --consumer-group snuba-gen-metrics-sets-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + profiles: + - feature-complete snuba-generic-metrics-counters-consumer: <<: *snuba_defaults command: rust-consumer --storage generic_metrics_counters_raw --consumer-group snuba-gen-metrics-counters-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + profiles: + - feature-complete snuba-generic-metrics-gauges-consumer: <<: *snuba_defaults command: rust-consumer --storage generic_metrics_gauges_raw --consumer-group snuba-gen-metrics-gauges-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset - snuba-replacer: - <<: *snuba_defaults - command: replacer --storage errors --auto-offset-reset=latest --no-strict-offset-reset - snuba-subscription-consumer-events: - <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset events --entity events --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-events-subscriptions-consumers --followed-consumer-group=snuba-consumers --schedule-ttl=60 --stale-threshold-seconds=900 - snuba-subscription-consumer-transactions: - <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset transactions --entity transactions --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-transactions-subscriptions-consumers --followed-consumer-group=transactions_group --schedule-ttl=60 --stale-threshold-seconds=900 - snuba-subscription-consumer-metrics: - <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset metrics --entity metrics_sets --entity metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-metrics-subscriptions-consumers --followed-consumer-group=snuba-metrics-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + profiles: + - feature-complete snuba-profiling-profiles-consumer: <<: *snuba_defaults command: rust-consumer --storage profiles --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + profiles: + - feature-complete snuba-profiling-functions-consumer: <<: *snuba_defaults command: rust-consumer --storage functions_raw --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + profiles: + - feature-complete snuba-spans-consumer: <<: *snuba_defaults command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + profiles: + - feature-complete symbolicator: <<: *restart_policy image: "$SYMBOLICATOR_IMAGE" @@ -363,57 +377,90 @@ services: attachments-consumer: <<: *sentry_defaults command: run consumer ingest-attachments --consumer-group ingest-consumer + post-process-forwarder-errors: + <<: *sentry_defaults + command: run consumer --no-strict-offset-reset post-process-forwarder-errors --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-commit-log --synchronize-commit-group=snuba-consumers + subscription-consumer-events: + <<: *sentry_defaults + command: run consumer events-subscription-results --consumer-group query-subscription-consumer + ############################################## + ## Feature Complete Sentry Ingest Consumers ## + ############################################## transactions-consumer: <<: *sentry_defaults command: run consumer ingest-transactions --consumer-group ingest-consumer + profiles: + - feature-complete metrics-consumer: <<: *sentry_defaults command: run consumer ingest-metrics --consumer-group metrics-consumer + profiles: + - feature-complete generic-metrics-consumer: <<: *sentry_defaults command: run consumer ingest-generic-metrics --consumer-group generic-metrics-consumer + profiles: + - feature-complete billing-metrics-consumer: <<: *sentry_defaults command: run consumer billing-metrics-consumer --consumer-group billing-metrics-consumer + profiles: + - feature-complete ingest-replay-recordings: <<: *sentry_defaults command: run consumer ingest-replay-recordings --consumer-group ingest-replay-recordings + profiles: + - feature-complete ingest-occurrences: <<: *sentry_defaults command: run consumer ingest-occurrences --consumer-group ingest-occurrences + profiles: + - feature-complete ingest-profiles: <<: *sentry_defaults command: run consumer ingest-profiles --consumer-group ingest-profiles + profiles: + - feature-complete ingest-monitors: <<: *sentry_defaults command: run consumer ingest-monitors --consumer-group ingest-monitors + profiles: + - feature-complete monitors-clock-tick: <<: *sentry_defaults command: run consumer monitors-clock-tick --consumer-group monitors-clock-tick + profiles: + - feature-complete monitors-clock-tasks: <<: *sentry_defaults command: run consumer monitors-clock-tasks --consumer-group monitors-clock-tasks - post-process-forwarder-errors: - <<: *sentry_defaults - command: run consumer --no-strict-offset-reset post-process-forwarder-errors --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-commit-log --synchronize-commit-group=snuba-consumers + profiles: + - feature-complete post-process-forwarder-transactions: <<: *sentry_defaults command: run consumer --no-strict-offset-reset post-process-forwarder-transactions --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-transactions-commit-log --synchronize-commit-group transactions_group + profiles: + - feature-complete post-process-forwarder-issue-platform: <<: *sentry_defaults command: run consumer --no-strict-offset-reset post-process-forwarder-issue-platform --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-generic-events-commit-log --synchronize-commit-group generic_events_group - subscription-consumer-events: - <<: *sentry_defaults - command: run consumer events-subscription-results --consumer-group query-subscription-consumer + profiles: + - feature-complete subscription-consumer-transactions: <<: *sentry_defaults command: run consumer transactions-subscription-results --consumer-group query-subscription-consumer + profiles: + - feature-complete subscription-consumer-metrics: <<: *sentry_defaults command: run consumer metrics-subscription-results --consumer-group query-subscription-consumer + profiles: + - feature-complete subscription-consumer-generic-metrics: <<: *sentry_defaults command: run consumer generic-metrics-subscription-results --consumer-group query-subscription-consumer + profiles: + - feature-complete sentry-cleanup: <<: *sentry_defaults image: sentry-cleanup-self-hosted-local @@ -469,6 +516,8 @@ services: depends_on: kafka: <<: *depends_on-healthy + profiles: + - feature-complete vroom-cleanup: <<: *restart_policy image: vroom-cleanup-self-hosted-local @@ -484,6 +533,8 @@ services: command: '"0 0 * * * find /var/lib/sentry-profiles -type f -mtime +$SENTRY_EVENT_RETENTION_DAYS -delete"' volumes: - sentry-vroom:/var/lib/sentry-profiles + profiles: + - feature-complete volumes: # These store application data that should persist across restarts. diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 38a461f46cb..0f8d611700d 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -363,3 +363,6 @@ def get_internal_network(): # https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS # CSRF_TRUSTED_ORIGINS = ["https://example.com", "http://127.0.0.1:9000"] + +# If you would like to use self-hosted Sentry with only errors enabled, please set this +SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") == "feature-complete" From fd2f9fa74ca906bb48b7d51fb5fa14d8bc7e1fc6 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Tue, 23 Jul 2024 11:14:55 -0700 Subject: [PATCH 041/305] Fix: errors only config flag (#3220) fix bug with errors only flag --- sentry/sentry.conf.example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 0f8d611700d..144d94b6be2 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -365,4 +365,4 @@ def get_internal_network(): # CSRF_TRUSTED_ORIGINS = ["https://example.com", "http://127.0.0.1:9000"] # If you would like to use self-hosted Sentry with only errors enabled, please set this -SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") == "feature-complete" +SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" From f330f3040d3ab81055f92b4ac4265fbbfe17487c Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 23 Jul 2024 19:39:00 +0000 Subject: [PATCH 042/305] release: 24.7.1 --- .env | 10 +++++----- CHANGELOG.md | 8 ++++++++ README.md | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 430cdac1d5d..d663c61b1ec 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.7.1 +SNUBA_IMAGE=getsentry/snuba:24.7.1 +RELAY_IMAGE=getsentry/relay:24.7.1 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.7.1 +VROOM_IMAGE=getsentry/vroom:24.7.1 WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/CHANGELOG.md b/CHANGELOG.md index 9490a34b78f..8925d795cd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 24.7.1 + +### Various fixes & improvements + +- Fix: errors only config flag (#3220) by @hubertdeng123 +- Add errors only self-hosted infrastructure (#3190) by @hubertdeng123 +- feat(generic-metrics): Add gauges to docker compose, re-try (#3177) by @ayirr7 + ## 24.7.0 ### Various fixes & improvements diff --git a/README.md b/README.md index 7315466c250..2ce9171dde7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry nightly +# Self-Hosted Sentry 24.7.1 Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From 22605fd745efcad217293ff3d041d146de699156 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 23 Jul 2024 20:04:25 +0000 Subject: [PATCH 043/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index d663c61b1ec..430cdac1d5d 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.7.1 -SNUBA_IMAGE=getsentry/snuba:24.7.1 -RELAY_IMAGE=getsentry/relay:24.7.1 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.7.1 -VROOM_IMAGE=getsentry/vroom:24.7.1 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/README.md b/README.md index 2ce9171dde7..7315466c250 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry 24.7.1 +# Self-Hosted Sentry nightly Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From cd7c460e15f7986bf206c3ea4c7e6cafa607604f Mon Sep 17 00:00:00 2001 From: Alex Bouma Date: Tue, 30 Jul 2024 22:29:14 +0200 Subject: [PATCH 044/305] Use CDN by default for JS SDK Loader (#3213) Co-authored-by: Hubert Deng --- sentry/sentry.conf.example.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 144d94b6be2..d39be661dbc 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -364,5 +364,12 @@ def get_internal_network(): # CSRF_TRUSTED_ORIGINS = ["https://example.com", "http://127.0.0.1:9000"] +################# +# JS SDK Loader # +################# + +JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle%s.min.js" + + # If you would like to use self-hosted Sentry with only errors enabled, please set this SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" From 0b11564e3652607baab6ec614f777517057ddfee Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 2 Aug 2024 02:01:17 +0700 Subject: [PATCH 045/305] feat: enable user feedback feature (#3193) * feat: enable user feedback feature --- docker-compose.yml | 5 +++++ sentry/sentry.conf.example.py | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index af7aab1d2de..ce67c1a72e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -426,6 +426,11 @@ services: command: run consumer ingest-monitors --consumer-group ingest-monitors profiles: - feature-complete + ingest-feedback-events: + <<: *sentry_defaults + command: run consumer ingest-feedback-events --consumer-group ingest-feedback + profiles: + - feature-complete monitors-clock-tick: <<: *sentry_defaults command: run consumer monitors-clock-tick --consumer-group monitors-clock-tick diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index d39be661dbc..a200124f833 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -293,6 +293,7 @@ def get_internal_network(): "projects:rate-limits", "projects:servicehooks", ) + # Starfish related flags + ( "organizations:deprecate-fid-from-performance-score", "organizations:indexed-spans-extraction", @@ -311,10 +312,23 @@ def get_internal_network(): "organizations:starfish-mobile-appstart", "projects:span-metrics-extraction", "projects:span-metrics-extraction-addons", - ) # starfish related flags + ) + # User Feedback related flags + + ( + "organizations:user-feedback-ingest", + "organizations:user-feedback-replay-clip", + "organizations:user-feedback-ui", + "organizations:feedback-visible", + "organizations:feedback-ingest", + "organizations:feedback-post-process-group", + ) } ) +# Temporary flag to mark User Feedback to be produced to the dedicated feedback topic by relay. +# This will be removed at a later time after it's considered stable and fully rolled out. +SENTRY_OPTIONS["feedback.ingest-topic.rollout-rate"] = 1.0 + ####################### # MaxMind Integration # ####################### From 20af97258a41e0ca87af532eb614180accc94eb0 Mon Sep 17 00:00:00 2001 From: anthony sottile <103459774+asottile-sentry@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:07:42 -0400 Subject: [PATCH 046/305] remove python-dev (#3242) this package does not exist on modern debians, the headers are already available in the docker image anyway resolves #3226 --- sentry/enhance-image.example.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/enhance-image.example.sh b/sentry/enhance-image.example.sh index e5b31826462..3f43756dd73 100755 --- a/sentry/enhance-image.example.sh +++ b/sentry/enhance-image.example.sh @@ -3,5 +3,5 @@ # Enhance the base $SENTRY_IMAGE with additional dependencies, plugins - see https://github.com/getsentry/self-hosted#enhance-sentry-image # For example: # apt-get update -# apt-get install -y gcc libsasl2-dev python-dev libldap2-dev libssl-dev +# apt-get install -y gcc libsasl2-dev libldap2-dev libssl-dev # pip install python-ldap From 053f4010b61adf4677d8ac81488d41dd95461fba Mon Sep 17 00:00:00 2001 From: anthony sottile <103459774+asottile-sentry@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:15:51 -0400 Subject: [PATCH 047/305] add `-euo pipefail` to enhance-image.example.sh (#3246) --- sentry/enhance-image.example.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry/enhance-image.example.sh b/sentry/enhance-image.example.sh index 3f43756dd73..c3ae96c96da 100755 --- a/sentry/enhance-image.example.sh +++ b/sentry/enhance-image.example.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -euo pipefail # Enhance the base $SENTRY_IMAGE with additional dependencies, plugins - see https://github.com/getsentry/self-hosted#enhance-sentry-image # For example: From 534a874c0bb8808d16001aa2d230e098993e82a5 Mon Sep 17 00:00:00 2001 From: Michal Kuffa Date: Mon, 12 Aug 2024 18:12:37 +0200 Subject: [PATCH 048/305] Remove cdc and wal2json and use the default postgres entrypoint (#3260) * Remove cdc and wal2json and use the default postgres entrypoint * Remove the last bits of wal2json install * Remove read-only postgres volume bind --- .env | 1 - .gitignore | 3 --- docker-compose.yml | 11 -------- install.sh | 1 - install/install-wal2json.sh | 45 -------------------------------- postgres/init_hba.sh | 7 ----- postgres/postgres-entrypoint.sh | 46 --------------------------------- scripts/bump-version.sh | 4 --- 8 files changed, 118 deletions(-) delete mode 100644 install/install-wal2json.sh delete mode 100755 postgres/init_hba.sh delete mode 100755 postgres/postgres-entrypoint.sh diff --git a/.env b/.env index 430cdac1d5d..db8bdb8dba2 100644 --- a/.env +++ b/.env @@ -11,7 +11,6 @@ SNUBA_IMAGE=getsentry/snuba:nightly RELAY_IMAGE=getsentry/relay:nightly SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly VROOM_IMAGE=getsentry/vroom:nightly -WAL2JSON_VERSION=latest HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/.gitignore b/.gitignore index 7311a09ae9c..13f8982c056 100644 --- a/.gitignore +++ b/.gitignore @@ -98,9 +98,6 @@ geoip/GeoIP.conf geoip/*.mmdb geoip/.geoipupdate.lock -# wal2json download -postgres/wal2json - # integration testing _integration-test/custom-ca-roots/nginx/* sentry/test-custom-ca-roots.py diff --git a/docker-compose.yml b/docker-compose.yml index ce67c1a72e2..654220d4ded 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -126,23 +126,12 @@ services: [ "postgres", "-c", - "wal_level=logical", - "-c", - "max_replication_slots=1", - "-c", - "max_wal_senders=1", - "-c", "max_connections=${POSTGRES_MAX_CONNECTIONS:-100}", ] environment: POSTGRES_HOST_AUTH_METHOD: "trust" - entrypoint: /opt/sentry/postgres-entrypoint.sh volumes: - "sentry-postgres:/var/lib/postgresql/data" - - type: bind - read_only: true - source: ./postgres/ - target: /opt/sentry/ zookeeper: <<: *restart_policy image: "confluentinc/cp-zookeeper:7.6.1" diff --git a/install.sh b/install.sh index ac5a2f0f4b2..ee2e008d1e7 100755 --- a/install.sh +++ b/install.sh @@ -32,7 +32,6 @@ source install/ensure-relay-credentials.sh source install/generate-secret-key.sh source install/update-docker-images.sh source install/build-docker-images.sh -source install/install-wal2json.sh source install/bootstrap-snuba.sh source install/upgrade-postgres.sh source install/set-up-and-migrate-database.sh diff --git a/install/install-wal2json.sh b/install/install-wal2json.sh deleted file mode 100644 index 9df0df7603e..00000000000 --- a/install/install-wal2json.sh +++ /dev/null @@ -1,45 +0,0 @@ -echo "${_group}Downloading and installing wal2json ..." - -WAL2JSON_DIR=postgres/wal2json -FILE_TO_USE="$WAL2JSON_DIR/wal2json.so" -ARCH=$(uname -m) -FILE_NAME="wal2json-Linux-$ARCH-glibc.so" - -docker_curl() { - # The environment variables can be specified in lower case or upper case. - # The lower case version has precedence. http_proxy is an exception as it is only available in lower case. - docker run --rm -e http_proxy -e https_proxy -e HTTPS_PROXY -e no_proxy -e NO_PROXY curlimages/curl:7.77.0 \ - --connect-timeout 5 \ - --max-time 10 \ - --retry 5 \ - --retry-max-time 60 \ - "$@" -} - -if [[ $WAL2JSON_VERSION == "latest" ]]; then - # Hard-code this. Super-hacky. We were curling the GitHub API here but - # hitting rate limits in CI. This library hasn't seen a new release for a - # year and a half at time of writing. - # - # If you're reading this do us a favor and go check: - # - # https://github.com/getsentry/wal2json/releases - # - # If there's a new release can you update this please? If not maybe subscribe - # for notifications on the repo with "Watch > Custom > Releases". Together we - # can make a difference. - VERSION=0.0.2 -else - VERSION=$WAL2JSON_VERSION -fi - -mkdir -p "$WAL2JSON_DIR" -if [ ! -f "$WAL2JSON_DIR/$VERSION/$FILE_NAME" ]; then - mkdir -p "$WAL2JSON_DIR/$VERSION" - docker_curl -L \ - "https://github.com/getsentry/wal2json/releases/download/$VERSION/$FILE_NAME" \ - >"$WAL2JSON_DIR/$VERSION/$FILE_NAME" -fi -cp "$WAL2JSON_DIR/$VERSION/$FILE_NAME" "$FILE_TO_USE" - -echo "${_endgroup}" diff --git a/postgres/init_hba.sh b/postgres/init_hba.sh deleted file mode 100755 index 9952ab14864..00000000000 --- a/postgres/init_hba.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -# Initializes the pg_hba file with access permissions to the replication -# slots. - -set -e - -{ echo "host replication all all trust"; } >>"$PGDATA/pg_hba.conf" diff --git a/postgres/postgres-entrypoint.sh b/postgres/postgres-entrypoint.sh deleted file mode 100755 index 68a469f7cae..00000000000 --- a/postgres/postgres-entrypoint.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -# This script replaces the default docker entrypoint for postgres in the -# development environment. -# Its job is to ensure postgres is properly configured to support the -# Change Data Capture pipeline (by setting access permissions and installing -# the replication plugin we use for CDC). Unfortunately the default -# Postgres image does not allow this level of configurability so we need -# to do it this way in order not to have to publish and maintain our own -# Postgres image. -# -# This then, at the end, transfers control to the default entrypoint. - -set -e - -prep_init_db() { - cp /opt/sentry/init_hba.sh /docker-entrypoint-initdb.d/init_hba.sh -} - -cdc_setup_hba_conf() { - # Ensure pg-hba is properly configured to allow connections - # to the replication slots. - - PG_HBA="$PGDATA/pg_hba.conf" - if [ ! -f "$PG_HBA" ]; then - echo "DB not initialized. Postgres will take care of pg_hba" - elif [ "$(grep -c -E "^host\s+replication" "$PGDATA"/pg_hba.conf)" != 0 ]; then - echo "Replication config already present in pg_hba. Not changing anything." - else - # Execute the same script we run on DB initialization - /opt/sentry/init_hba.sh - fi -} - -bind_wal2json() { - # Copy the file in the right place - cp /opt/sentry/wal2json/wal2json.so $(pg_config --pkglibdir)/wal2json.so -} - -echo "Setting up Change Data Capture" - -prep_init_db -if [ "$1" = 'postgres' ]; then - cdc_setup_hba_conf - bind_wal2json -fi -exec /usr/local/bin/docker-entrypoint.sh "$@" diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index e59a1d1eb27..808df09aa17 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -4,11 +4,7 @@ set -eu OLD_VERSION="$1" NEW_VERSION="$2" -WAL2JSON_VERSION=${WAL2JSON_VERSION:-$(curl -s "https://api.github.com/repos/getsentry/wal2json/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')} - -sed -i -e "s/^WAL2JSON_VERSION=\([^:]\+\):.\+\$/WAL2JSON_VERSION=\1:$WAL2JSON_VERSION/" .env sed -i -e "s/^\(SENTRY\|SNUBA\|RELAY\|SYMBOLICATOR\|VROOM\)_IMAGE=\([^:]\+\):.\+\$/\1_IMAGE=\2:$NEW_VERSION/" .env sed -i -e "s/^\# Self-Hosted Sentry .*/# Self-Hosted Sentry $NEW_VERSION/" README.md echo "New version: $NEW_VERSION" -echo "New wal2json version: $WAL2JSON_VERSION" From d64f72fafaf5937636df29fd108d471c63671aeb Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:05:26 -0700 Subject: [PATCH 049/305] ref(feedback): cleanup topic rollout option (#3256) --- sentry/sentry.conf.example.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index a200124f833..f20c4efdcb6 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -325,10 +325,6 @@ def get_internal_network(): } ) -# Temporary flag to mark User Feedback to be produced to the dedicated feedback topic by relay. -# This will be removed at a later time after it's considered stable and fully rolled out. -SENTRY_OPTIONS["feedback.ingest-topic.rollout-rate"] = 1.0 - ####################### # MaxMind Integration # ####################### From 9b815ac58d202f84904dc40eaad3aac689644f79 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:55:04 -0700 Subject: [PATCH 050/305] Revert "ref(feedback): cleanup topic rollout option" (#3262) Revert "ref(feedback): cleanup topic rollout option (#3256)" This reverts commit d64f72fafaf5937636df29fd108d471c63671aeb. --- sentry/sentry.conf.example.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index f20c4efdcb6..a200124f833 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -325,6 +325,10 @@ def get_internal_network(): } ) +# Temporary flag to mark User Feedback to be produced to the dedicated feedback topic by relay. +# This will be removed at a later time after it's considered stable and fully rolled out. +SENTRY_OPTIONS["feedback.ingest-topic.rollout-rate"] = 1.0 + ####################### # MaxMind Integration # ####################### From 0ce7b00b2aa5709b4a8582896fd8658ea0ae72be Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Tue, 13 Aug 2024 14:14:11 -0700 Subject: [PATCH 051/305] Migrate to zookeeper-less kafka (#3263) * migrate to kraft * fix syntax error * move zookeeper volume removal to end of installation --- _unit-test/create-docker-volumes-test.sh | 3 +- docker-compose.yml | 40 +++++++----------------- install/create-docker-volumes.sh | 1 - install/wrap-up.sh | 5 +++ 4 files changed, 17 insertions(+), 32 deletions(-) diff --git a/_unit-test/create-docker-volumes-test.sh b/_unit-test/create-docker-volumes-test.sh index 6b1176c5c73..2cb9b962a8b 100755 --- a/_unit-test/create-docker-volumes-test.sh +++ b/_unit-test/create-docker-volumes-test.sh @@ -14,8 +14,7 @@ sentry-data sentry-kafka sentry-postgres sentry-redis -sentry-symbolicator -sentry-zookeeper" +sentry-symbolicator" before=$(get_volumes) diff --git a/docker-compose.yml b/docker-compose.yml index 654220d4ded..be219e31138 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -132,42 +132,27 @@ services: POSTGRES_HOST_AUTH_METHOD: "trust" volumes: - "sentry-postgres:/var/lib/postgresql/data" - zookeeper: - <<: *restart_policy - image: "confluentinc/cp-zookeeper:7.6.1" - environment: - ZOOKEEPER_CLIENT_PORT: "2181" - CONFLUENT_SUPPORT_METRICS_ENABLE: "false" - ZOOKEEPER_LOG4J_ROOT_LOGLEVEL: "WARN" - ZOOKEEPER_TOOLS_LOG4J_LOGLEVEL: "WARN" - KAFKA_OPTS: "-Dzookeeper.4lw.commands.whitelist=ruok" - ulimits: - nofile: - soft: 4096 - hard: 4096 - volumes: - - "sentry-zookeeper:/var/lib/zookeeper/data" - - "sentry-zookeeper-log:/var/lib/zookeeper/log" - - "sentry-secrets:/etc/zookeeper/secrets" - healthcheck: - <<: *healthcheck_defaults - test: ["CMD-SHELL", 'echo "ruok" | nc -w 2 localhost 2181 | grep imok'] kafka: <<: *restart_policy - depends_on: - zookeeper: - <<: *depends_on-healthy image: "confluentinc/cp-kafka:7.6.1" environment: - KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" - KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092" + # https://docs.confluent.io/platform/current/installation/docker/config-reference.html#cp-kakfa-example + KAFKA_PROCESS_ROLES: "broker,controller" + KAFKA_CONTROLLER_QUORUM_VOTERS: "1001@127.0.0.1:29093" + KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER" + KAFKA_NODE_ID: "1001" + CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk" + KAFKA_LISTENERS: "PLAINTEXT://0.0.0.0:29092,INTERNAL://0.0.0.0:9093,EXTERNAL://0.0.0.0:9092,CONTROLLER://0.0.0.0:29093" + KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://127.0.0.1:29092,INTERNAL://kafka:9093,EXTERNAL://kafka:9092" + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "PLAINTEXT:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT" + KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT" KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1" KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS: "1" KAFKA_LOG_RETENTION_HOURS: "24" KAFKA_MESSAGE_MAX_BYTES: "50000000" #50MB or bust KAFKA_MAX_REQUEST_SIZE: "50000000" #50MB on requests apparently too CONFLUENT_SUPPORT_METRICS_ENABLE: "false" - KAFKA_LOG4J_LOGGERS: "kafka.cluster=WARN,kafka.controller=WARN,kafka.coordinator=WARN,kafka.log=WARN,kafka.server=WARN,kafka.zookeeper=WARN,state.change.logger=WARN" + KAFKA_LOG4J_LOGGERS: "kafka.cluster=WARN,kafka.controller=WARN,kafka.coordinator=WARN,kafka.log=WARN,kafka.server=WARN,state.change.logger=WARN" KAFKA_LOG4J_ROOT_LOGLEVEL: "WARN" KAFKA_TOOLS_LOG4J_LOGLEVEL: "WARN" ulimits: @@ -538,8 +523,6 @@ volumes: external: true sentry-redis: external: true - sentry-zookeeper: - external: true sentry-kafka: external: true sentry-clickhouse: @@ -555,7 +538,6 @@ volumes: sentry-secrets: sentry-smtp: sentry-nginx-cache: - sentry-zookeeper-log: sentry-kafka-log: sentry-smtp-log: sentry-clickhouse-log: diff --git a/install/create-docker-volumes.sh b/install/create-docker-volumes.sh index ca3ef0b23ed..15f20d54409 100644 --- a/install/create-docker-volumes.sh +++ b/install/create-docker-volumes.sh @@ -6,6 +6,5 @@ echo "Created $(docker volume create --name=sentry-kafka)." echo "Created $(docker volume create --name=sentry-postgres)." echo "Created $(docker volume create --name=sentry-redis)." echo "Created $(docker volume create --name=sentry-symbolicator)." -echo "Created $(docker volume create --name=sentry-zookeeper)." echo "${_endgroup}" diff --git a/install/wrap-up.sh b/install/wrap-up.sh index a811f81a618..8840262f25d 100644 --- a/install/wrap-up.sh +++ b/install/wrap-up.sh @@ -28,3 +28,8 @@ else echo "-----------------------------------------------------------------" echo "" fi + +# TODO(getsentry/self-hosted#2489) +if docker volume ls | grep -qw sentry-zookeeper; then + docker volume rm sentry-zookeeper +fi From b7ed3cb8b05c5f0e3f1d77b9ba970ae672bae0b7 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 15 Aug 2024 18:06:05 +0000 Subject: [PATCH 052/305] release: 24.8.0 --- .env | 10 +++++----- CHANGELOG.md | 13 +++++++++++++ README.md | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.env b/.env index db8bdb8dba2..79a394e0426 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.8.0 +SNUBA_IMAGE=getsentry/snuba:24.8.0 +RELAY_IMAGE=getsentry/relay:24.8.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.8.0 +VROOM_IMAGE=getsentry/vroom:24.8.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8925d795cd2..f13da018e5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 24.8.0 + +### Various fixes & improvements + +- Migrate to zookeeper-less kafka (#3263) by @hubertdeng123 +- Revert "ref(feedback): cleanup topic rollout option" (#3262) by @aliu39 +- ref(feedback): cleanup topic rollout option (#3256) by @aliu39 +- Remove cdc and wal2json and use the default postgres entrypoint (#3260) by @beezz +- add `-euo pipefail` to enhance-image.example.sh (#3246) by @asottile-sentry +- remove python-dev (#3242) by @asottile-sentry +- feat: enable user feedback feature (#3193) by @aldy505 +- Use CDN by default for JS SDK Loader (#3213) by @stayallive + ## 24.7.1 ### Various fixes & improvements diff --git a/README.md b/README.md index 7315466c250..5fb7b56e10a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry nightly +# Self-Hosted Sentry 24.8.0 Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From 2d8d3495bdacb1e1e05530b4b5023c275de9f47e Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Thu, 15 Aug 2024 11:49:41 -0700 Subject: [PATCH 053/305] Update release template (#3270) update release template --- .github/ISSUE_TEMPLATE/release.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/release.yml b/.github/ISSUE_TEMPLATE/release.yml index c8285b5409e..48691f3255d 100644 --- a/.github/ISSUE_TEMPLATE/release.yml +++ b/.github/ISSUE_TEMPLATE/release.yml @@ -10,10 +10,8 @@ body: [previous YY.M.N](https://github.com/getsentry/self-hosted/issues) | ***YY.M.N*** | [next YY.M.N](https://github.com/getsentry/self-hosted/issues) - [ ] Release all components (_replace items with [publish repo issue links](https://github.com/getsentry/publish/issues)_). - - [ ] [`develop`](https://github.com/getsentry/develop/actions/workflows/prepare-release.yml) - [ ] [`relay`](https://github.com/getsentry/relay/actions/workflows/release_binary.yml) - [ ] [`sentry`](https://github.com/getsentry/sentry/actions/workflows/release.yml) - - [ ] [`sentry-docs`](https://github.com/getsentry/sentry-docs/actions/workflows/prepare-release.yml) - [ ] [`snuba`](https://github.com/getsentry/snuba/actions/workflows/release.yml) - [ ] [`symbolicator`](https://github.com/getsentry/symbolicator/actions/workflows/release.yml) - [ ] [`vroom`](https://github.com/getsentry/vroom/actions/workflows/release.yaml) @@ -25,7 +23,6 @@ body: - [ ] Follow up. - [ ] [Create the next release issue](https://github.com/getsentry/self-hosted/issues/new?assignees=&labels=&projects=&template=release.yml) and link it from this one. - _replace with link_ - - [ ] Update the [quarterly ticket](https://github.com/getsentry/team-ospo/issues). - [ ] Update the [release issue template](https://github.com/getsentry/self-hosted/blob/master/.github/ISSUE_TEMPLATE/release.yml). - [ ] Create a PR to update relocation release tests to add the new version. - _replace with link_ From 9b56d6293f7628a19a3b762a6c4faa1be50e04a4 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 15 Aug 2024 20:10:34 +0000 Subject: [PATCH 054/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- README.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 79a394e0426..db8bdb8dba2 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.8.0 -SNUBA_IMAGE=getsentry/snuba:24.8.0 -RELAY_IMAGE=getsentry/relay:24.8.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.8.0 -VROOM_IMAGE=getsentry/vroom:24.8.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/README.md b/README.md index 5fb7b56e10a..7315466c250 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Self-Hosted Sentry 24.8.0 +# Self-Hosted Sentry nightly Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). From 8595228be3b56aa33cf6d0327de0993bff29c747 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:58:28 -0700 Subject: [PATCH 055/305] ref(feedback): cleanup topic rollout option (#3276) --- sentry/sentry.conf.example.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index a200124f833..f20c4efdcb6 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -325,10 +325,6 @@ def get_internal_network(): } ) -# Temporary flag to mark User Feedback to be produced to the dedicated feedback topic by relay. -# This will be removed at a later time after it's considered stable and fully rolled out. -SENTRY_OPTIONS["feedback.ingest-topic.rollout-rate"] = 1.0 - ####################### # MaxMind Integration # ####################### From b6de547e45aef7897e635620f54cc09769de6bba Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Sat, 17 Aug 2024 12:26:50 -0700 Subject: [PATCH 056/305] Mandate minimum requirements for ram/cpu (#3275) --- install/_min-requirements.sh | 6 ++---- install/check-minimum-requirements.sh | 4 ---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/install/_min-requirements.sh b/install/_min-requirements.sh index f8836db0863..ae0b7c01a85 100644 --- a/install/_min-requirements.sh +++ b/install/_min-requirements.sh @@ -1,7 +1,5 @@ # Don't forget to update the README and othes docs when you change these! MIN_DOCKER_VERSION='19.03.6' MIN_COMPOSE_VERSION='2.19.0' -MIN_RAM_HARD=3800 # MB -MIN_RAM_SOFT=7800 # MB -MIN_CPU_HARD=2 -MIN_CPU_SOFT=4 +MIN_RAM_HARD=15900 # MB +MIN_CPU_HARD=4 diff --git a/install/check-minimum-requirements.sh b/install/check-minimum-requirements.sh index 01488e8d176..47848cc2859 100644 --- a/install/check-minimum-requirements.sh +++ b/install/check-minimum-requirements.sh @@ -36,16 +36,12 @@ CPU_AVAILABLE_IN_DOCKER=$(docker run --rm busybox nproc --all) if [[ "$CPU_AVAILABLE_IN_DOCKER" -lt "$MIN_CPU_HARD" ]]; then echo "FAIL: Required minimum CPU cores available to Docker is $MIN_CPU_HARD, found $CPU_AVAILABLE_IN_DOCKER" exit 1 -elif [[ "$CPU_AVAILABLE_IN_DOCKER" -lt "$MIN_CPU_SOFT" ]]; then - echo "WARN: Recommended minimum CPU cores available to Docker is $MIN_CPU_SOFT, found $CPU_AVAILABLE_IN_DOCKER" fi RAM_AVAILABLE_IN_DOCKER=$(docker run --rm busybox free -m 2>/dev/null | awk '/Mem/ {print $2}') if [[ "$RAM_AVAILABLE_IN_DOCKER" -lt "$MIN_RAM_HARD" ]]; then echo "FAIL: Required minimum RAM available to Docker is $MIN_RAM_HARD MB, found $RAM_AVAILABLE_IN_DOCKER MB" exit 1 -elif [[ "$RAM_AVAILABLE_IN_DOCKER" -lt "$MIN_RAM_SOFT" ]]; then - echo "WARN: Recommended minimum RAM available to Docker is $MIN_RAM_SOFT MB, found $RAM_AVAILABLE_IN_DOCKER MB" fi #SSE4.2 required by Clickhouse (https://clickhouse.yandex/docs/en/operations/requirements/) From 3cf323843ab9e63515bd2816a426bd5116324834 Mon Sep 17 00:00:00 2001 From: joshuarli Date: Fri, 23 Aug 2024 12:32:52 -0700 Subject: [PATCH 057/305] fix: more leeway for minimum RAM (#3290) more generous leeway --- install/_min-requirements.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/install/_min-requirements.sh b/install/_min-requirements.sh index ae0b7c01a85..2180c6a9a97 100644 --- a/install/_min-requirements.sh +++ b/install/_min-requirements.sh @@ -1,5 +1,9 @@ -# Don't forget to update the README and othes docs when you change these! +# Don't forget to update the README and other docs when you change these! MIN_DOCKER_VERSION='19.03.6' MIN_COMPOSE_VERSION='2.19.0' -MIN_RAM_HARD=15900 # MB + +# 16 GB minimum host RAM, but there'll be some overhead outside of what +# can be allotted to docker +MIN_RAM_HARD=14000 # MB + MIN_CPU_HARD=4 From b8b4aa20aa7aa4e37a8a2569d70ca54d450ae947 Mon Sep 17 00:00:00 2001 From: joshuarli Date: Tue, 3 Sep 2024 12:55:40 -0700 Subject: [PATCH 058/305] docs: link to develop docs (#3307) --- README.md | 82 ++----------------------------------------------------- 1 file changed, 3 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 7315466c250..a8f1fef5b1a 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,5 @@ -# Self-Hosted Sentry nightly +# Self-Hosted Sentry -Official bootstrap for running your own [Sentry](https://sentry.io/) with [Docker](https://www.docker.com/). +[Sentry](https://sentry.io/), feature-complete and packaged up for low-volume deployments and proofs-of-concept. -## Requirements - -* Docker 19.03.6+ -* Compose 2.19.0+ -* 4 CPU Cores -* 16 GB RAM -* 20 GB Free Disk Space - -## Setup - -### Installation - -To get started with all the defaults, simply clone the repo and run `./install.sh` in your local check-out. Please also read the section below about monitoring. Sentry uses Python 3 by default since December 4th, 2020 and Sentry 21.1.0 is the last version to support Python 2. - -During the install, a prompt will ask if you want to create a user account. If you require that the install goes on without creating a user, run `./install.sh --skip-user-creation`. - -Thinking of not managing this yourself? Check out the [SaaS migration docs](https://docs.sentry.io/product/sentry-basics/migration/) or [contact us](https://sentry.io/from/self-hosted) for help. - -Please visit [our documentation](https://develop.sentry.dev/self-hosted/) for everything else. - -### Customize DotEnv (.env) file - -Environment specific configurations can be done in the `.env.custom` file. It will be located in the root directory of the Sentry installation, and if it exists then `.env` will be ignored entirely. - -By default, there exists no `.env.custom` file. In this case, you can manually add this file by copying the `.env` file to a new `.env.custom` file and adjust your settings in the `.env.custom` file. - -Please keep in mind to check the `.env` file for changes, when you perform an upgrade of Sentry, so that you can adjust your `.env.custom` accordingly, if required, as `.env` is ignored entirely if `.env.custom` is present. - -### Enhance Sentry image - -To install plugins and their dependencies or make other modifications to the Sentry base image, -copy `sentry/enhance-image.example.sh` to `sentry/enhance-image.sh` and add necessary steps there. -For example, you can use `apt-get` to install dependencies and use `pip` to install plugins. - -After making modifications to `sentry/enhance-image.sh`, run `./install.sh` again to apply them. - -## Tips & Tricks - -### Event Retention - -Sentry comes with a cleanup cron job that prunes events older than `90 days` by default. If you want to change that, you can change the `SENTRY_EVENT_RETENTION_DAYS` environment variable in `.env` or simply override it in your environment. If you do not want the cleanup cron, you can remove the `sentry-cleanup` service from the `docker-compose.yml`file. - -### Installing a specific SHA - -If you want to install a specific release of Sentry, use the tags/releases on this repo. - -We continuously push the Docker image for each commit made into [Sentry](https://github.com/getsentry/sentry), and other services such as [Snuba](https://github.com/getsentry/snuba) or [Symbolicator](https://github.com/getsentry/symbolicator) to [our Docker Hub](https://hub.docker.com/u/getsentry) and tag the latest version on master as `:nightly`. This is also usually what we have on sentry.io and what the install script uses. You can use a custom Sentry image, such as a modified version that you have built on your own, or simply a specific commit hash by setting the `SENTRY_IMAGE` environment variable to that image name before running `./install.sh`: - -```shell -SENTRY_IMAGE=getsentry/sentry:83b1380 ./install.sh -``` - -Note that this may not work for all commit SHAs as this repository evolves with Sentry and its satellite projects. It is highly recommended to check out a version of this repository that is close to the timestamp of the Sentry commit you are installing. - -### Using Linux - -If you are using Linux and you need to use `sudo` when running `./install.sh`, make sure to place the environment variable *after* `sudo`: - -```shell -sudo SENTRY_IMAGE=us.gcr.io/sentryio/sentry:83b1380 ./install.sh -``` - -Where you replace `83b1380` with the sha you want to use. - -### Self-Hosted Monitoring - -We'd love to catch errors in self-hosted so you don't run into them, and so we can fix them faster! When you run `./install.sh`, you will be prompted to select whether to opt in or out of our monitoring. If you opt into our monitoring, we will send information to our own self-hosted Sentry instance for development and debugging purposes. We may collect: - -- OS username -- IP address -- install log -- runtime errors in Sentry -- performance data - -Thirty (30) day retention. No marketing. Privacy policy at sentry.io/privacy. - -Starting with the 22.10.0 release in October, we will require those running the Sentry installer to choose to opt in or out. If you are running the installer under automation, you may want to set `REPORT_SELF_HOSTED_ISSUES` or pass `--(no-)report-self-hosted-issues` to the installer accordingly. +Documentation [here](https://develop.sentry.dev/self-hosted/). From 8887a82a86153d0c9696463c0525976cf8e3f136 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sun, 15 Sep 2024 18:05:44 +0000 Subject: [PATCH 059/305] release: 24.9.0 --- .env | 10 +++++----- CHANGELOG.md | 10 ++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.env b/.env index db8bdb8dba2..5adf46197a9 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.9.0 +SNUBA_IMAGE=getsentry/snuba:24.9.0 +RELAY_IMAGE=getsentry/relay:24.9.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.9.0 +VROOM_IMAGE=getsentry/vroom:24.9.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index f13da018e5e..5ff69d1f2ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 24.9.0 + +### Various fixes & improvements + +- docs: link to develop docs (#3307) by @joshuarli +- fix: more leeway for minimum RAM (#3290) by @joshuarli +- Mandate minimum requirements for ram/cpu (#3275) by @hubertdeng123 +- ref(feedback): cleanup topic rollout option (#3276) by @aliu39 +- Update release template (#3270) by @hubertdeng123 + ## 24.8.0 ### Various fixes & improvements From 5bd6cd3710cc214b2d68858d24a7d6bcf8149d73 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 16 Sep 2024 22:55:23 +0000 Subject: [PATCH 060/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 5adf46197a9..db8bdb8dba2 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.9.0 -SNUBA_IMAGE=getsentry/snuba:24.9.0 -RELAY_IMAGE=getsentry/relay:24.9.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.9.0 -VROOM_IMAGE=getsentry/vroom:24.9.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 036f6d49e9b4388d81a0bc907ea0e274ba55c401 Mon Sep 17 00:00:00 2001 From: Nikhar Saxena <84807402+nikhars@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:00:32 -0700 Subject: [PATCH 061/305] fix(clickhouse): Allow nullable key (#3354) --- clickhouse/config.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clickhouse/config.xml b/clickhouse/config.xml index 19a0ecf80a9..28ec384cb62 100644 --- a/clickhouse/config.xml +++ b/clickhouse/config.xml @@ -16,6 +16,8 @@ + 1 + 0 From 5910c02cc404e533348de84d99acb6d9f7b85530 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 8 Oct 2024 06:03:28 +0700 Subject: [PATCH 062/305] ref: allow hosted js sdk bundles (#3365) * ref: allow hosted js sdk bundles --------- Co-authored-by: Burak Yigit Kaya --- .env | 2 ++ _unit-test/js-sdk-assets-test.sh | 26 ++++++++++++++++++++++ docker-compose.yml | 4 ++++ install.sh | 1 + install/setup-js-sdk-assets.sh | 38 ++++++++++++++++++++++++++++++++ nginx/nginx.conf | 4 ++++ sentry/sentry.conf.example.py | 11 +++++++++ 7 files changed, 86 insertions(+) create mode 100755 _unit-test/js-sdk-assets-test.sh create mode 100644 install/setup-js-sdk-assets.sh diff --git a/.env b/.env index db8bdb8dba2..58e11832a61 100644 --- a/.env +++ b/.env @@ -17,3 +17,5 @@ HEALTHCHECK_RETRIES=10 # Caution: Raising max connections of postgres increases CPU and RAM usage # see https://github.com/getsentry/self-hosted/pull/2740 for more information POSTGRES_MAX_CONNECTIONS=100 +# Set SETUP_JS_SDK_ASSETS to 1 to enable the setup of JS SDK assets +# SETUP_JS_SDK_ASSETS=1 diff --git a/_unit-test/js-sdk-assets-test.sh b/_unit-test/js-sdk-assets-test.sh new file mode 100755 index 00000000000..5355a57076d --- /dev/null +++ b/_unit-test/js-sdk-assets-test.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +source _unit-test/_test_setup.sh +source install/dc-detect-version.sh +$dcb --force-rm web + +export SETUP_JS_SDK_ASSETS=1 + +source install/setup-js-sdk-assets.sh + +sdk_files=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx ls -lah /var/www/js-sdk/) +sdk_tree=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx tree /var/www/js-sdk/ | tail -n 1) + +# `sdk_files` should contains 2 lines, `7.*` and `8.*` +echo $sdk_files +total_directories=$(echo "$sdk_files" | grep -c '[78]\.[0-9]*\.[0-9]*$') +echo $total_directories +test "2" == "$total_directories" +echo "Pass" + +# `sdk_tree` should outputs "2 directories, 10 files" +echo "$sdk_tree" +test "2 directories, 10 files" == "$(echo "$sdk_tree")" +echo "Pass" + +report_success diff --git a/docker-compose.yml b/docker-compose.yml index be219e31138..e38d4af0f36 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -460,6 +460,7 @@ services: source: ./nginx target: /etc/nginx - sentry-nginx-cache:/var/cache/nginx + - sentry-nginx-www:/var/www depends_on: - web - relay @@ -529,6 +530,9 @@ volumes: external: true sentry-symbolicator: external: true + # This volume stores JS SDK assets and the data inside this volume should + # be cleaned periodically on upgrades. + sentry-nginx-www: # This volume stores profiles and should be persisted. # Not being external will still persist data across restarts. # It won't persist if someone does a docker compose down -v. diff --git a/install.sh b/install.sh index ee2e008d1e7..e9460d36ceb 100755 --- a/install.sh +++ b/install.sh @@ -36,4 +36,5 @@ source install/bootstrap-snuba.sh source install/upgrade-postgres.sh source install/set-up-and-migrate-database.sh source install/geoip.sh +source install/setup-js-sdk-assets.sh source install/wrap-up.sh diff --git a/install/setup-js-sdk-assets.sh b/install/setup-js-sdk-assets.sh new file mode 100644 index 00000000000..c8521ce8a52 --- /dev/null +++ b/install/setup-js-sdk-assets.sh @@ -0,0 +1,38 @@ +# This will only run if the SETUP_JS_SDK_ASSETS environment variable is set to 1. +# Think of this as some kind of a feature flag. +if [[ "${SETUP_JS_SDK_ASSETS:-}" == "1" ]]; then + echo "${_group}Setting up JS SDK assets" + + # If the `sentry-nginx-www` volume exists, we need to prune the contents. + # We don't want to fill the volume with old JS SDK assets. + # If people want to keep the old assets, they can set the environment variable + # `SETUP_JS_SDK_KEEP_OLD_ASSETS` to any value. + if [[ -z "${SETUP_JS_SDK_KEEP_OLD_ASSETS:-}" ]]; then + echo "Cleaning up old JS SDK assets..." + $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx rm -rf /var/www/js-sdk/* + fi + + $dbuild -t sentry-self-hosted-jq-local --platform="$DOCKER_PLATFORM" jq + + jq="docker run --rm -i sentry-self-hosted-jq-local" + + loader_registry=$($dcr --no-deps --rm -T web cat /usr/src/sentry/src/sentry/loader/_registry.json) + # The `loader_registry` should start with "Updating certificates...", we want to delete that and the subsequent ca-certificates related lines. + # We want to remove everything before the first '{'. + loader_registry=$(echo "$loader_registry" | sed '0,/{/s/[^{]*//') + + latest_js_v7=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("7.")))) | .[0]') + latest_js_v8=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("8.")))) | .[0]') + + echo "Found JS SDKs v${latest_js_v7} and v${latest_js_v8}, downloading from upstream.." + + # Download those two using wget + for version in "${latest_js_v7}" "${latest_js_v8}"; do + $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx mkdir -p /var/www/js-sdk/${version} + for variant in "tracing" "tracing.replay" "replay" "tracing.replay.feedback" "feedback"; do + $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx wget -q -O /var/www/js-sdk/${version}/bundle.${variant}.min.js "https://browser.sentry-cdn.com/${version}/bundle.${variant}.min.js" + done + done + + echo "${_endgroup}" +fi diff --git a/nginx/nginx.conf b/nginx/nginx.conf index c24fe7ec188..66bb4301e82 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -88,6 +88,10 @@ http { location ^~ /api/0/relays/ { proxy_pass http://relay; } + location ^~ /js-sdk/ { + autoindex on; + root /var/www/js-sdk; + } location / { proxy_pass http://sentry; } diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index f20c4efdcb6..bb3b4fd5d9b 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -378,6 +378,17 @@ def get_internal_network(): # JS SDK Loader # ################# +# Configure Sentry JS SDK bundle URL template for Loader Scripts. +# Learn more about the Loader Scripts: https://docs.sentry.io/platforms/javascript/install/loader/ + +# If you wish to host your own JS SDK bundles, set `SETUP_JS_SDK_ASSETS` environment variable to `1` +# on your `.env` or `.env.custom` file. Then, replace the value below with your own public URL. +# For example: "https://sentry.example.com/js-sdk/%s/bundle%s.min.js" +# +# By default, the previous JS SDK assets version will be pruned during upgrades, if you wish +# to keep the old assets, set `SETUP_JS_SDK_KEEP_OLD_ASSETS` environment variable to any value on +# your `.env` or `.env.custom` file. The files should only be a few KBs, and this might be useful +# if you're using it directly like a CDN instead of using the loader script. JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle%s.min.js" From cba2d4b236548cfe8964bc8cdaa576a4fcdc112a Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 9 Oct 2024 01:54:07 +0700 Subject: [PATCH 063/305] docs: explicitly specify `mail.use-{tls,ssl}` is mutually exclusive (#3368) --- sentry/config.example.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry/config.example.yml b/sentry/config.example.yml index de0b68b99f8..d5a6dc322ce 100644 --- a/sentry/config.example.yml +++ b/sentry/config.example.yml @@ -12,6 +12,8 @@ mail.host: 'smtp' # mail.port: 25 # mail.username: '' # mail.password: '' +# NOTE: `mail.use-tls` and `mail.use-ssl` are mutually exclusive and should not +# appear at the same time. Only uncomment one of them. # mail.use-tls: false # mail.use-ssl: false @@ -19,7 +21,6 @@ mail.host: 'smtp' # through SENTRY_MAIL_HOST in sentry.conf.py so remove those first if # you want your values in this file to be effective! - # The email address to send on behalf of # mail.from: 'root@localhost' or ... # mail.from: 'System Administrator ' From 9a2f4e184452aa11fde5b2edbea5ea101f0ee5fe Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 10 Oct 2024 21:54:39 +0700 Subject: [PATCH 064/305] ref: span normalization allowed host config (#3245) Co-authored-by: Hubert Deng --- sentry/sentry.conf.example.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index bb3b4fd5d9b..222acf0a878 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -380,7 +380,6 @@ def get_internal_network(): # Configure Sentry JS SDK bundle URL template for Loader Scripts. # Learn more about the Loader Scripts: https://docs.sentry.io/platforms/javascript/install/loader/ - # If you wish to host your own JS SDK bundles, set `SETUP_JS_SDK_ASSETS` environment variable to `1` # on your `.env` or `.env.custom` file. Then, replace the value below with your own public URL. # For example: "https://sentry.example.com/js-sdk/%s/bundle%s.min.js" @@ -394,3 +393,15 @@ def get_internal_network(): # If you would like to use self-hosted Sentry with only errors enabled, please set this SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" + +##################### +# Insights Settings # +##################### + +# Since version 24.3.0, Insights features are available on self-hosted. For Requests module, +# there are scrubbing logic done on Relay to prevent high cardinality of stored HTTP hosts. +# However in self-hosted scenario, the amount of stored HTTP hosts might be consistent, +# and you may have allow list of hosts that you want to keep. Uncomment the following line +# to allow specific hosts. It might be IP addresses or domain names (without `http://` or `https://`). + +# SENTRY_OPTIONS["relay.span-normalization.allowed_hosts"] = ["example.com", "192.168.10.1"] From bdf8d3ff918d92b04d10906f3869900ca41ec3bf Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 10 Oct 2024 16:55:58 +0200 Subject: [PATCH 065/305] chore: replace old URLs of the repo with the new docs (#3375) --- sentry/Dockerfile | 2 +- sentry/enhance-image.example.sh | 2 +- sentry/entrypoint.sh | 2 +- sentry/requirements.example.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sentry/Dockerfile b/sentry/Dockerfile index 5afe9c2dd86..557046f143d 100644 --- a/sentry/Dockerfile +++ b/sentry/Dockerfile @@ -8,6 +8,6 @@ RUN if [ -s /usr/src/sentry/enhance-image.sh ]; then \ fi RUN if [ -s /usr/src/sentry/requirements.txt ]; then \ - echo "sentry/requirements.txt is deprecated, use sentry/enhance-image.sh - see https://github.com/getsentry/self-hosted#enhance-sentry-image"; \ + echo "sentry/requirements.txt is deprecated, use sentry/enhance-image.sh - see https://develop.sentry.dev/self-hosted/#enhance-sentry-image"; \ pip install -r /usr/src/sentry/requirements.txt; \ fi diff --git a/sentry/enhance-image.example.sh b/sentry/enhance-image.example.sh index c3ae96c96da..de17136d9c9 100755 --- a/sentry/enhance-image.example.sh +++ b/sentry/enhance-image.example.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -# Enhance the base $SENTRY_IMAGE with additional dependencies, plugins - see https://github.com/getsentry/self-hosted#enhance-sentry-image +# Enhance the base $SENTRY_IMAGE with additional dependencies, plugins - see https://develop.sentry.dev/self-hosted/#enhance-sentry-image # For example: # apt-get update # apt-get install -y gcc libsasl2-dev libldap2-dev libssl-dev diff --git a/sentry/entrypoint.sh b/sentry/entrypoint.sh index 552de05b69a..7be738fdd7e 100755 --- a/sentry/entrypoint.sh +++ b/sentry/entrypoint.sh @@ -6,7 +6,7 @@ if [ "$(ls -A /usr/local/share/ca-certificates/)" ]; then fi if [ -e /etc/sentry/requirements.txt ]; then - echo "sentry/requirements.txt is deprecated, use sentry/enhance-image.sh - see https://github.com/getsentry/self-hosted#enhance-sentry-image" + echo "sentry/requirements.txt is deprecated, use sentry/enhance-image.sh - see https://develop.sentry.dev/self-hosted/#enhance-sentry-image" fi source /docker-entrypoint.sh diff --git a/sentry/requirements.example.txt b/sentry/requirements.example.txt index e7b63dc9a67..393a2f52fc3 100644 --- a/sentry/requirements.example.txt +++ b/sentry/requirements.example.txt @@ -1 +1 @@ -# sentry/requirements.txt is deprecated, use sentry/enhance-image.sh - see https://github.com/getsentry/self-hosted#enhance-sentry-image +# sentry/requirements.txt is deprecated, use sentry/enhance-image.sh - see https://develop.sentry.dev/self-hosted/#enhance-sentry-image From 73f9f0067264bcbb541bf1c5ca57520abd542e68 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Thu, 17 Oct 2024 14:17:20 -0700 Subject: [PATCH 066/305] chore: Disable codecov for master/release branches (#3384) * disable codecov for master/release branches * add new line * use default project * also do changes for patch --- codecov.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000000..ed9aed0e588 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,8 @@ +coverage: + status: + project: + default: + only_pulls: true + patch: + default: + only_pulls: true From a29a7969f5f7a93e27c67f0aa622452b5ddc2687 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 17 Oct 2024 21:17:47 +0000 Subject: [PATCH 067/305] release: 24.10.0 --- .env | 10 +++++----- CHANGELOG.md | 11 +++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 58e11832a61..01d06061204 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.10.0 +SNUBA_IMAGE=getsentry/snuba:24.10.0 +RELAY_IMAGE=getsentry/relay:24.10.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.10.0 +VROOM_IMAGE=getsentry/vroom:24.10.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ff69d1f2ea..8c738fe7ab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 24.10.0 + +### Various fixes & improvements + +- chore: Disable codecov for master/release branches (#3384) by @hubertdeng123 +- chore: replace old URLs of the repo with the new docs (#3375) by @victorelec14 +- ref: span normalization allowed host config (#3245) by @aldy505 +- docs: explicitly specify `mail.use-{tls,ssl}` is mutually exclusive (#3368) by @aldy505 +- ref: allow hosted js sdk bundles (#3365) by @aldy505 +- fix(clickhouse): Allow nullable key (#3354) by @nikhars + ## 24.9.0 ### Various fixes & improvements From f0f854c6f44bff0c47366fd788e95243473f2072 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 17 Oct 2024 21:43:41 +0000 Subject: [PATCH 068/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 01d06061204..58e11832a61 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.10.0 -SNUBA_IMAGE=getsentry/snuba:24.10.0 -RELAY_IMAGE=getsentry/relay:24.10.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.10.0 -VROOM_IMAGE=getsentry/vroom:24.10.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 8fd24d02312f9fd7990c1ad0808d561c7b4f80b5 Mon Sep 17 00:00:00 2001 From: Daniil Makhonia <32175481+Makhonya@users.noreply.github.com> Date: Fri, 18 Oct 2024 21:09:31 +0200 Subject: [PATCH 069/305] fix(sentry-admin): Do not wait for command finish to display output (#3390) Currently sentry-admin.sh script saves the output of the command to a separate variable. This makes the command "freeze" if it requires any input from the user (like sentry-admin.sh restore). The change should provide the output directly to the shell. Also changed contributing.md as it seemed outdated and updated requirements-dev.txt with the missing `cryptography` package. Co-authored-by: Daniil Makhonia --- CONTRIBUTING.md | 12 +++++++++--- requirements-dev.txt | 1 + sentry-admin.sh | 3 +-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49120afa854..3c3e987b2a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,13 @@ ## Testing -Validate changes to the setup by running the integration test: +### Running Tests with Pytest -```shell -./integration-test.sh +We use pytest for running tests. To run the tests: + +1) Ensure that you are in the root directory of the project. +2) Run the following command: +```bash +pytest ``` + +This will automatically discover and run all test cases in the project. diff --git a/requirements-dev.txt b/requirements-dev.txt index 42bf67b2472..62b4166f202 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,3 +5,4 @@ pytest-rerunfailures>=11.0 pytest-sentry>=0.1.11 httpx>=0.25.2 beautifulsoup4>=4.7.1 +cryptography>=43.0.3 diff --git a/sentry-admin.sh b/sentry-admin.sh index d162c82114d..d775e905e94 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -22,8 +22,7 @@ on the host filesystem. Commands that write files should write them to the '/sen # Actual invocation that runs the command in the container. invocation() { - output=$($dc run -v "$VOLUME_MAPPING" --rm -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1) - echo "$output" + $dc run -v "$VOLUME_MAPPING" --rm -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 } # Function to modify lines starting with `Usage: sentry` to say `Usage: ./sentry-admin.sh` instead. From 72c5e59ed41e966cf4e0857b69d9258ff16e2ea4 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Mon, 28 Oct 2024 09:58:38 -0700 Subject: [PATCH 070/305] ref(feedback): remove issue platform flags after releasing issue types (#3397) --- sentry/sentry.conf.example.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 222acf0a878..28403d69451 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -318,9 +318,6 @@ def get_internal_network(): "organizations:user-feedback-ingest", "organizations:user-feedback-replay-clip", "organizations:user-feedback-ui", - "organizations:feedback-visible", - "organizations:feedback-ingest", - "organizations:feedback-post-process-group", ) } ) From 7574a49542319aab09c879a17ac40658e9f6d0d9 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 28 Oct 2024 20:02:23 +0000 Subject: [PATCH 071/305] Revert "ref(feedback): remove issue platform flags after releasing issue types" (#3402) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "ref(feedback): remove issue platform flags after releasing issue type…" This reverts commit 72c5e59ed41e966cf4e0857b69d9258ff16e2ea4. https://github.com/getsentry/self-hosted/pull/3397#issuecomment-2442142424 --- sentry/sentry.conf.example.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 28403d69451..222acf0a878 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -318,6 +318,9 @@ def get_internal_network(): "organizations:user-feedback-ingest", "organizations:user-feedback-replay-clip", "organizations:user-feedback-ui", + "organizations:feedback-visible", + "organizations:feedback-ingest", + "organizations:feedback-post-process-group", ) } ) From db21c6cc5552d5279a9e5594c6860dd6f6382b52 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 31 Oct 2024 22:32:29 +0000 Subject: [PATCH 072/305] Revert "Revert "ref(feedback): remove issue platform flags after releasing issue types"" (#3403) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "Revert "ref(feedback): remove issue platform flags after releasing is…" This reverts commit 7574a49542319aab09c879a17ac40658e9f6d0d9. --- sentry/sentry.conf.example.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 222acf0a878..28403d69451 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -318,9 +318,6 @@ def get_internal_network(): "organizations:user-feedback-ingest", "organizations:user-feedback-replay-clip", "organizations:user-feedback-ui", - "organizations:feedback-visible", - "organizations:feedback-ingest", - "organizations:feedback-post-process-group", ) } ) From 2a7abf215e6e1d2973ff457856e67488a72248be Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 7 Nov 2024 17:11:07 +0700 Subject: [PATCH 073/305] fix(loader): provide js sdk assets from 4.x (#3415) Hopefully fixes https://github.com/getsentry/sentry/issues/22715#issuecomment-2458066842 ### Legal Boilerplate Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. --- _unit-test/js-sdk-assets-test.sh | 10 +++++----- install/setup-js-sdk-assets.sh | 26 +++++++++++++++++++++----- unit-test.sh | 5 +++-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/_unit-test/js-sdk-assets-test.sh b/_unit-test/js-sdk-assets-test.sh index 5355a57076d..30c2f07e466 100755 --- a/_unit-test/js-sdk-assets-test.sh +++ b/_unit-test/js-sdk-assets-test.sh @@ -11,16 +11,16 @@ source install/setup-js-sdk-assets.sh sdk_files=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx ls -lah /var/www/js-sdk/) sdk_tree=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx tree /var/www/js-sdk/ | tail -n 1) -# `sdk_files` should contains 2 lines, `7.*` and `8.*` +# `sdk_files` should contains 5 lines, '4.*', '5.*', '6.*', `7.*` and `8.*` echo $sdk_files -total_directories=$(echo "$sdk_files" | grep -c '[78]\.[0-9]*\.[0-9]*$') +total_directories=$(echo "$sdk_files" | grep -c '[45678]\.[0-9]*\.[0-9]*$') echo $total_directories -test "2" == "$total_directories" +test "5" == "$total_directories" echo "Pass" -# `sdk_tree` should outputs "2 directories, 10 files" +# `sdk_tree` should output "5 directories, 17 files" echo "$sdk_tree" -test "2 directories, 10 files" == "$(echo "$sdk_tree")" +test "5 directories, 17 files" == "$(echo "$sdk_tree")" echo "Pass" report_success diff --git a/install/setup-js-sdk-assets.sh b/install/setup-js-sdk-assets.sh index c8521ce8a52..f9261393f5e 100644 --- a/install/setup-js-sdk-assets.sh +++ b/install/setup-js-sdk-assets.sh @@ -21,16 +21,32 @@ if [[ "${SETUP_JS_SDK_ASSETS:-}" == "1" ]]; then # We want to remove everything before the first '{'. loader_registry=$(echo "$loader_registry" | sed '0,/{/s/[^{]*//') + # Sentry backend provides SDK versions from v4.x up to v8.x. + latest_js_v4=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("4.")))) | .[0]') + latest_js_v5=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("5.")))) | .[0]') + latest_js_v6=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("6.")))) | .[0]') latest_js_v7=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("7.")))) | .[0]') latest_js_v8=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("8.")))) | .[0]') - echo "Found JS SDKs v${latest_js_v7} and v${latest_js_v8}, downloading from upstream.." + echo "Found JS SDKs: v${latest_js_v4}, v${latest_js_v5}, v${latest_js_v6}, v${latest_js_v7}, v${latest_js_v8}" - # Download those two using wget - for version in "${latest_js_v7}" "${latest_js_v8}"; do + versions=("$latest_js_v4" "$latest_js_v5" "$latest_js_v6" "$latest_js_v7" "$latest_js_v8") + variants=("bundle" "bundle.tracing" "bundle.tracing.replay" "bundle.replay" "bundle.tracing.replay.feedback" "bundle.feedback") + + # Download those versions & variants using curl + for version in "${versions[@]}"; do $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx mkdir -p /var/www/js-sdk/${version} - for variant in "tracing" "tracing.replay" "replay" "tracing.replay.feedback" "feedback"; do - $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx wget -q -O /var/www/js-sdk/${version}/bundle.${variant}.min.js "https://browser.sentry-cdn.com/${version}/bundle.${variant}.min.js" + for variant in "${variants[@]}"; do + # We want to have a HEAD lookup. If the response status code is not 200, we will skip the variant. + # Taken from https://superuser.com/questions/272265/getting-curl-to-output-http-status-code#comment1025992_272273 + status_code=$($dcr --no-deps --rm nginx curl --retry 5 -sLI "https://browser.sentry-cdn.com/${version}/${variant}.min.js" 2>/dev/null | head -n 1 | cut -d$' ' -f2) + if [[ "$status_code" != "200" ]]; then + echo "Skipping download of JS SDK v${version} for ${variant}.min.js, because the status code was ${status_code} (non 200)" + continue + fi + + echo "Downloading JS SDK v${version} for ${variant}.min.js..." + $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx curl --retry 10 -sLo /var/www/js-sdk/${version}/${variant}.min.js "https://browser.sentry-cdn.com/${version}/${variant}.min.js" done done diff --git a/unit-test.sh b/unit-test.sh index 6cb81fa8d20..01a945e3777 100755 --- a/unit-test.sh +++ b/unit-test.sh @@ -11,8 +11,9 @@ for test_file in _unit-test/*-test.sh; do fi echo "🙈 Running $test_file ..." $test_file - if [ $? != 0 ]; then - echo fail 👎 + exit_code=$? + if [ $exit_code != 0 ]; then + echo fail 👎 with exit code $exit_code fail=1 fi done From 49e30a7356aa0e2c58c7b0e1769dc0a98dcfd493 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 7 Nov 2024 12:25:53 +0000 Subject: [PATCH 074/305] fix: Use js.sentry-cdn.com for JS SDK downloads (#3417) Since we download JS SDKs in a for loop which invokes a separate docker container for each `curl` run, we seem to be triggering some sort of a DoS protection. And rightfully so as the old method causes TCP and TLS churn although we advertise we support HTTP/1.1 and HTTP/2. This patch does a few things: 1. Uses `curl`s globbing support to download all files in one go, maxing TCP and TLS reuse. This should fix the DoS protection 2. Uses `curl`'s `--compress` option to make things even more efficient 3. Uses `curl`'s `--create-dirs` to save 1 docker container run per version for creating the directory 4. Removes the `-I` `HEAD` checks in favor of a `-f` fail option combined with `|| true` which makes curl fail and not write the output on a non-200 response while still allowing the script to succeed 5. To make sure the above approach works, it adds a file size test, requiring all downloaded files to be larger than 1kB --- _unit-test/js-sdk-assets-test.sh | 6 ++++++ install/setup-js-sdk-assets.sh | 20 +++----------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/_unit-test/js-sdk-assets-test.sh b/_unit-test/js-sdk-assets-test.sh index 30c2f07e466..7177f559ba9 100755 --- a/_unit-test/js-sdk-assets-test.sh +++ b/_unit-test/js-sdk-assets-test.sh @@ -10,6 +10,7 @@ source install/setup-js-sdk-assets.sh sdk_files=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx ls -lah /var/www/js-sdk/) sdk_tree=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx tree /var/www/js-sdk/ | tail -n 1) +non_empty_file_count=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx find /var/www/js-sdk/ -type f -size +1k | wc -l) # `sdk_files` should contains 5 lines, '4.*', '5.*', '6.*', `7.*` and `8.*` echo $sdk_files @@ -23,4 +24,9 @@ echo "$sdk_tree" test "5 directories, 17 files" == "$(echo "$sdk_tree")" echo "Pass" +# Files should all be >1k (ensure they are not empty) +echo "Testing file sizes" +test "17" == "$non_empty_file_count" +echo "Pass" + report_success diff --git a/install/setup-js-sdk-assets.sh b/install/setup-js-sdk-assets.sh index f9261393f5e..50b9428dd4b 100644 --- a/install/setup-js-sdk-assets.sh +++ b/install/setup-js-sdk-assets.sh @@ -30,25 +30,11 @@ if [[ "${SETUP_JS_SDK_ASSETS:-}" == "1" ]]; then echo "Found JS SDKs: v${latest_js_v4}, v${latest_js_v5}, v${latest_js_v6}, v${latest_js_v7}, v${latest_js_v8}" - versions=("$latest_js_v4" "$latest_js_v5" "$latest_js_v6" "$latest_js_v7" "$latest_js_v8") - variants=("bundle" "bundle.tracing" "bundle.tracing.replay" "bundle.replay" "bundle.tracing.replay.feedback" "bundle.feedback") + versions="{$latest_js_v4,$latest_js_v5,$latest_js_v6,$latest_js_v7,$latest_js_v8}" + variants="{bundle,bundle.tracing,bundle.tracing.replay,bundle.replay,bundle.tracing.replay.feedback,bundle.feedback}" # Download those versions & variants using curl - for version in "${versions[@]}"; do - $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx mkdir -p /var/www/js-sdk/${version} - for variant in "${variants[@]}"; do - # We want to have a HEAD lookup. If the response status code is not 200, we will skip the variant. - # Taken from https://superuser.com/questions/272265/getting-curl-to-output-http-status-code#comment1025992_272273 - status_code=$($dcr --no-deps --rm nginx curl --retry 5 -sLI "https://browser.sentry-cdn.com/${version}/${variant}.min.js" 2>/dev/null | head -n 1 | cut -d$' ' -f2) - if [[ "$status_code" != "200" ]]; then - echo "Skipping download of JS SDK v${version} for ${variant}.min.js, because the status code was ${status_code} (non 200)" - continue - fi - - echo "Downloading JS SDK v${version} for ${variant}.min.js..." - $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx curl --retry 10 -sLo /var/www/js-sdk/${version}/${variant}.min.js "https://browser.sentry-cdn.com/${version}/${variant}.min.js" - done - done + $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx curl -w '%{response_code} %{url}\n' --no-progress-meter --compressed --retry 3 --create-dirs -fLo "/var/www/js-sdk/#1/#2.min.js" "https://browser.sentry-cdn.com/${versions}/${variants}.min.js" || true echo "${_endgroup}" fi From 98f6cf0a5dcf209139b0f71bf2a1a50ec672f58f Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 7 Nov 2024 20:25:50 +0700 Subject: [PATCH 075/305] fix: missing mime types and turning off autoindex for js-sdk endpoint (#3395) Things weren't as smooth as I thought it would be. ### Legal Boilerplate Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. --- docker-compose.yml | 4 ++-- nginx/nginx.conf => nginx.conf | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) rename nginx/nginx.conf => nginx.conf (88%) diff --git a/docker-compose.yml b/docker-compose.yml index e38d4af0f36..a899ae80410 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -457,8 +457,8 @@ services: volumes: - type: bind read_only: true - source: ./nginx - target: /etc/nginx + source: ./nginx.conf + target: /etc/nginx/nginx.conf - sentry-nginx-cache:/var/cache/nginx - sentry-nginx-www:/var/www depends_on: diff --git a/nginx/nginx.conf b/nginx.conf similarity index 88% rename from nginx/nginx.conf rename to nginx.conf index 66bb4301e82..32d9487f809 100644 --- a/nginx/nginx.conf +++ b/nginx.conf @@ -11,6 +11,7 @@ events { http { + include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' @@ -89,8 +90,10 @@ http { proxy_pass http://relay; } location ^~ /js-sdk/ { - autoindex on; - root /var/www/js-sdk; + root /var/www/; + # This value is set to mimic the behavior of the upstream Sentry CDN. For security reasons, + # it is recommended to change this to your Sentry URL (in most cases same as system.url-prefix). + add_header Access-Control-Allow-Origin *; } location / { proxy_pass http://sentry; From 6a8c3a47587bf23847e51a7de3a21d152f1b7064 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Mon, 11 Nov 2024 15:47:07 -0800 Subject: [PATCH 076/305] feat(healthcheck): Improve redis healthcheck (#3422) improve redis healthcheck --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index a899ae80410..9e4ae9dd730 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -107,7 +107,7 @@ services: image: "redis:6.2.14-alpine" healthcheck: <<: *healthcheck_defaults - test: redis-cli ping + test: redis-cli ping | grep PONG volumes: - "sentry-redis:/data" ulimits: From fa61f1707f8dd2c08622fa32695b3876bca80919 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Fri, 15 Nov 2024 18:06:09 +0000 Subject: [PATCH 077/305] release: 24.11.0 --- .env | 10 +++++----- CHANGELOG.md | 13 +++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 58e11832a61..329686f40a1 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.11.0 +SNUBA_IMAGE=getsentry/snuba:24.11.0 +RELAY_IMAGE=getsentry/relay:24.11.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.11.0 +VROOM_IMAGE=getsentry/vroom:24.11.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c738fe7ab9..79a21509417 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 24.11.0 + +### Various fixes & improvements + +- feat(healthcheck): Improve redis healthcheck (#3422) by @hubertdeng123 +- fix: missing mime types and turning off autoindex for js-sdk endpoint (#3395) by @aldy505 +- fix: Use js.sentry-cdn.com for JS SDK downloads (#3417) by @BYK +- fix(loader): provide js sdk assets from 4.x (#3415) by @aldy505 +- Revert "Revert "ref(feedback): remove issue platform flags after releasing issue types"" (#3403) by @BYK +- Revert "ref(feedback): remove issue platform flags after releasing issue types" (#3402) by @BYK +- ref(feedback): remove issue platform flags after releasing issue types (#3397) by @aliu39 +- fix(sentry-admin): Do not wait for command finish to display output (#3390) by @Makhonya + ## 24.10.0 ### Various fixes & improvements From 7cfab8db1ebfc115c32edce0bc242ccde7835d4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:41:33 +0000 Subject: [PATCH 078/305] build(deps): bump codecov/codecov-action from 4 to 5 (#3429) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v4...v5) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e565392c897..291e78c7c8f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -147,7 +147,7 @@ jobs: docker compose logs - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} slug: getsentry/self-hosted From be66069eefe7b703e977af7f3d64d5002a549631 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 19 Nov 2024 02:09:53 +0000 Subject: [PATCH 079/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 329686f40a1..58e11832a61 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.11.0 -SNUBA_IMAGE=getsentry/snuba:24.11.0 -RELAY_IMAGE=getsentry/relay:24.11.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.11.0 -VROOM_IMAGE=getsentry/vroom:24.11.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From c3814f08077ce42428af4c583699f810e8dba78e Mon Sep 17 00:00:00 2001 From: Sajjad hassanzadeh <32982356+Hassanzadeh-sd@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:13:58 +0330 Subject: [PATCH 080/305] feat: add Redis configuration for improved memory management (#3427) As Sentry continues to evolve, effective resource management becomes crucial for maintaining performance and stability. This update includes configurations that will help optimize Redis's memory usage, ensuring that the system runs efficiently under varying loads. **Key Changes:** - **Added `maxmemory` Directive**: Configured Redis to limit its memory usage to a specified size. This prevents excessive memory consumption and helps maintain system stability. - **Set `maxmemory-policy` to `allkeys-lru`**: This policy allows Redis to evict the least recently used keys when it reaches the memory limit, ensuring that frequently accessed data remains available while older, less-used data is removed. --- docker-compose.yml | 4 ++++ redis.conf | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 redis.conf diff --git a/docker-compose.yml b/docker-compose.yml index 9e4ae9dd730..b11db2d79aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -110,6 +110,10 @@ services: test: redis-cli ping | grep PONG volumes: - "sentry-redis:/data" + - type: bind + read_only: true + source: ./redis.conf + target: /usr/local/etc/redis/redis.conf ulimits: nofile: soft: 10032 diff --git a/redis.conf b/redis.conf new file mode 100644 index 00000000000..25103a88119 --- /dev/null +++ b/redis.conf @@ -0,0 +1,26 @@ +# redis.conf + +# The 'maxmemory' directive controls the maximum amount of memory Redis is allowed to use. +# Setting 'maxmemory 0' means there is no limit on memory usage, allowing Redis to use as much +# memory as the operating system allows. This is suitable for environments where memory +# constraints are not a concern. +# +# Alternatively, you can specify a limit, such as 'maxmemory 15gb', to restrict Redis to +# using a maximum of 15 gigabytes of memory. +# +# Example: +# maxmemory 0 # Unlimited memory usage +# maxmemory 15gb # Limit memory usage to 15 GB + +maxmemory 0 + +# maxmemory-policy allkeys-lru +# +# This setting determines how Redis evicts keys when it reaches the memory limit. +# 'allkeys-lru' evicts the least recently used keys from all keys stored in Redis, +# allowing frequently accessed data to remain in memory while older data is removed. +# +# Example: +# maxmemory-policy allkeys-lru # Use LRU eviction for all keys + +maxmemory-policy allkeys-lru From 0b0d0c8e541f1f758213e092df72115866455648 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 19 Nov 2024 16:34:41 +0000 Subject: [PATCH 081/305] fix(redis): Use a safer eviction rule (#3432) Follow up to https://github.com/getsentry/self-hosted/pull/3427#issuecomment-2485612688 --- redis.conf | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/redis.conf b/redis.conf index 25103a88119..090b148b15e 100644 --- a/redis.conf +++ b/redis.conf @@ -14,13 +14,14 @@ maxmemory 0 -# maxmemory-policy allkeys-lru -# # This setting determines how Redis evicts keys when it reaches the memory limit. -# 'allkeys-lru' evicts the least recently used keys from all keys stored in Redis, +# `allkeys-lru` evicts the least recently used keys from all keys stored in Redis, # allowing frequently accessed data to remain in memory while older data is removed. -# -# Example: -# maxmemory-policy allkeys-lru # Use LRU eviction for all keys +# That said we use `volatile-lru` as Redis is used both as a cache and processing +# queue in self-hosted Sentry. +# > The volatile-lru and volatile-random policies are mainly useful when you want to +# > use a single Redis instance for both caching and for a set of persistent keys. +# > However, you should consider running two separate Redis instances in a case like +# > this, if possible. -maxmemory-policy allkeys-lru +maxmemory-policy volatile-lru From 99f715461873c70601bc60913c7652e58bff463b Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 26 Nov 2024 17:27:18 +0000 Subject: [PATCH 082/305] release: 24.11.1 --- .env | 10 +++++----- CHANGELOG.md | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 58e11832a61..c24a2cf4249 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.11.1 +SNUBA_IMAGE=getsentry/snuba:24.11.1 +RELAY_IMAGE=getsentry/relay:24.11.1 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.11.1 +VROOM_IMAGE=getsentry/vroom:24.11.1 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 79a21509417..7b9eeb94db2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 24.11.1 + +### Various fixes & improvements + +- fix(redis): Use a safer eviction rule (#3432) by @BYK +- feat: add Redis configuration for improved memory management (#3427) by @Hassanzadeh-sd +- build(deps): bump codecov/codecov-action from 4 to 5 (#3429) by @dependabot + ## 24.11.0 ### Various fixes & improvements From be02e0e4000e4e4f494eb778afe66e8378ace210 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 26 Nov 2024 17:56:03 +0000 Subject: [PATCH 083/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index c24a2cf4249..58e11832a61 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.11.1 -SNUBA_IMAGE=getsentry/snuba:24.11.1 -RELAY_IMAGE=getsentry/relay:24.11.1 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.11.1 -VROOM_IMAGE=getsentry/vroom:24.11.1 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 817fde205f8ed7820f5343c059e8e7e40e69842f Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 28 Nov 2024 00:53:07 +0700 Subject: [PATCH 084/305] ref: remove suggested fix (#3446) --- docker-compose.yml | 1 - sentry/sentry.conf.example.py | 14 -------------- 2 files changed, 15 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b11db2d79aa..0710ee41e18 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -59,7 +59,6 @@ x-sentry-defaults: &sentry_defaults SENTRY_EVENT_RETENTION_DAYS: SENTRY_MAIL_HOST: SENTRY_MAX_EXTERNAL_SOURCEMAP_SIZE: - OPENAI_API_KEY: volumes: - "sentry-data:/data" - "./sentry:/etc/sentry" diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 28403d69451..27f6ad02c2a 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -335,20 +335,6 @@ def get_internal_network(): # BITBUCKET_CONSUMER_KEY = 'YOUR_BITBUCKET_CONSUMER_KEY' # BITBUCKET_CONSUMER_SECRET = 'YOUR_BITBUCKET_CONSUMER_SECRET' -############################################## -# Suggested Fix Feature / OpenAI Integration # -############################################## - -# See https://docs.sentry.io/product/issues/issue-details/ai-suggested-solution/ -# for more information about the feature. Make sure the OpenAI's privacy policy is -# aligned with your company. - -# Set the OPENAI_API_KEY on the .env or .env.custom file with a valid -# OpenAI API key to turn on the feature. -OPENAI_API_KEY = env("OPENAI_API_KEY", "") - -SENTRY_FEATURES["organizations:open-ai-suggestion"] = bool(OPENAI_API_KEY) - ############################################## # Content Security Policy settings ############################################## From bc0816cda60324e7db7ef5f7838aed30d99820c7 Mon Sep 17 00:00:00 2001 From: niklassc7 <44340628+niklassc7@users.noreply.github.com> Date: Fri, 29 Nov 2024 11:05:05 +0100 Subject: [PATCH 085/305] add sentry/backup.json to gitignore (#3450) The backup-method described in the [documentation](https://develop.sentry.dev/self-hosted/backup/#backup) `./scripts/backup.sh` creates a backup file at `sentry/backup.json` which should be ignored by git. ### Legal Boilerplate Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 13f8982c056..26d3ff590b1 100644 --- a/.gitignore +++ b/.gitignore @@ -89,6 +89,7 @@ data/ sentry/sentry.conf.py sentry/config.yml sentry/*.bak +sentry/backup.json sentry/enhance-image.sh sentry/requirements.txt relay/credentials.json From 56db0dbbcb920e9dd02d418baab05a39b786ba57 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 30 Nov 2024 17:04:13 +0700 Subject: [PATCH 086/305] chore(issue-template): ask for machine specification and provide link to security policy (#3447) --- .github/ISSUE_TEMPLATE/problem-report.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/problem-report.yml b/.github/ISSUE_TEMPLATE/problem-report.yml index 53ac4ec2acb..1be5d3e4796 100644 --- a/.github/ISSUE_TEMPLATE/problem-report.yml +++ b/.github/ISSUE_TEMPLATE/problem-report.yml @@ -23,7 +23,7 @@ body: id: docker_version attributes: label: Docker Version - placeholder: 20.10.16 ← should look like this + placeholder: 20.10.16 ← should look like this (docker --version) description: | What version of docker are you using to run self-hosted? e.g: (docker --version) @@ -39,6 +39,16 @@ body: e.g: (docker compose version) validations: required: true + - type: checkboxes + id: machine_specification + attributes: + label: Machine Specification + description: Make sure your system meets the [minimum system requirements of Sentry](https://develop.sentry.dev/self-hosted/#required-minimum-system-resources). + options: + - label: My system meets the minimum system requirements of Sentry + required: true + validations: + required: true - type: textarea id: repro attributes: @@ -54,6 +64,8 @@ body: id: expected attributes: label: Expected Result + description: | + What did you expect to happen? validations: required: true - type: textarea @@ -70,7 +82,7 @@ body: - logs output validations: required: true - - type: textarea + - type: input id: event_id attributes: label: Event ID @@ -82,5 +94,7 @@ body: value: |- ## Thanks Check our [triage docs](https://open.sentry.io/triage/) for what to expect next. + + If you're reporting a security issue, please follow our [security policy](https://github.com/getsentry/.github/blob/main/SECURITY.md) instead. validations: required: false From e535c2b4b3dab2a3b92b18e65cb41bf6c8081141 Mon Sep 17 00:00:00 2001 From: Jeffrey Hung <17494876+Jeffreyhung@users.noreply.github.com> Date: Fri, 6 Dec 2024 01:55:28 -0800 Subject: [PATCH 087/305] feat(release): Replace release bot with GH app (#3458) * Replace release bot with GH app * remove unneeded app token --- .github/workflows/release.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4f6156bc1c..7899952fc0f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,15 +19,21 @@ jobs: runs-on: ubuntu-latest name: "Release a new version" steps: + - name: Get auth token + id: token + uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 + with: + app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} + private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} - uses: actions/checkout@v4 with: - token: ${{ secrets.GH_RELEASE_PAT }} + token: ${{ steps.token.outputs.token }} fetch-depth: 0 - name: Prepare release id: prepare-release uses: getsentry/action-prepare-release@v1 env: - GITHUB_TOKEN: ${{ secrets.GH_RELEASE_PAT }} + GITHUB_TOKEN: ${{ steps.token.outputs.token }} with: version: ${{ github.event.inputs.version }} force: ${{ github.event.inputs.force }} @@ -42,7 +48,6 @@ jobs: steps: - uses: actions/checkout@v4 with: - token: ${{ secrets.GH_RELEASE_PAT }} fetch-depth: 0 - uses: getsentry/action-release@v1 env: From 3834ca7a61b8f5ecbd1d461bf252e5b08afe6f6e Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 6 Dec 2024 10:55:11 +0000 Subject: [PATCH 088/305] fix(redis): Actually use custom config (#3459) Follow up to https://github.com/getsentry/self-hosted/pull/3427#issuecomment-2518128717 where we created and mounted a custom Redis config only to not use it :facepalm: --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 0710ee41e18..eeae00ee981 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -117,6 +117,7 @@ services: nofile: soft: 10032 hard: 10032 + command: ["redis-server", "/usr/local/etc/redis/redis.conf"] postgres: <<: *restart_policy # Using the same postgres version as Sentry dev for consistency purposes From 078507ba7e64e94998f09ab5808809356856ef83 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 11 Dec 2024 19:36:09 +0000 Subject: [PATCH 089/305] release: 24.11.2 --- .env | 10 +++++----- CHANGELOG.md | 10 ++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 58e11832a61..cae3f775a6f 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.11.2 +SNUBA_IMAGE=getsentry/snuba:24.11.2 +RELAY_IMAGE=getsentry/relay:24.11.2 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.11.2 +VROOM_IMAGE=getsentry/vroom:24.11.2 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b9eeb94db2..7679ba12e93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 24.11.2 + +### Various fixes & improvements + +- fix(redis): Actually use custom config (#3459) by @BYK +- feat(release): Replace release bot with GH app (#3458) by @Jeffreyhung +- chore(issue-template): ask for machine specification and provide link to security policy (#3447) by @aldy505 +- add sentry/backup.json to gitignore (#3450) by @niklassc7 +- ref: remove suggested fix (#3446) by @aldy505 + ## 24.11.1 ### Various fixes & improvements From 1f63d4d2e2122e5cbf58555c450c9d60e5e7f3bc Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 11 Dec 2024 21:48:37 +0000 Subject: [PATCH 090/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index cae3f775a6f..58e11832a61 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.11.2 -SNUBA_IMAGE=getsentry/snuba:24.11.2 -RELAY_IMAGE=getsentry/relay:24.11.2 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.11.2 -VROOM_IMAGE=getsentry/vroom:24.11.2 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 6ba735824a6fc5780083b1f339c82fade81a98cd Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sun, 15 Dec 2024 18:05:38 +0000 Subject: [PATCH 091/305] release: 24.12.0 --- .env | 10 +++++----- CHANGELOG.md | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 58e11832a61..90d98b2830d 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.12.0 +SNUBA_IMAGE=getsentry/snuba:24.12.0 +RELAY_IMAGE=getsentry/relay:24.12.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.12.0 +VROOM_IMAGE=getsentry/vroom:24.12.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7679ba12e93..c08109c3f9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 24.12.0 + +- No documented changes. + ## 24.11.2 ### Various fixes & improvements From 245f3d1a87c1b393b33eda444afc2dfa50e3f3ea Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 17 Dec 2024 23:39:36 +0000 Subject: [PATCH 092/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 90d98b2830d..58e11832a61 100644 --- a/.env +++ b/.env @@ -6,11 +6,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.12.0 -SNUBA_IMAGE=getsentry/snuba:24.12.0 -RELAY_IMAGE=getsentry/relay:24.12.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.12.0 -VROOM_IMAGE=getsentry/vroom:24.12.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 01d7741bc5ec174a5a23befb9ed2f75456890636 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 20 Dec 2024 22:32:29 +0300 Subject: [PATCH 093/305] fix(nginx): _assets should rewrite to _static/sentry/dist (#3483) Our default fallback, `_assets`, assumes we use a CDN which is not the case on self-hosted. This patch adds a stop-gap fix for front-end URLs asking for this path. Should fix #3479 and #3470. --- _integration-test/test_run.py | 8 ++++++++ nginx.conf | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/_integration-test/test_run.py b/_integration-test/test_run.py index 2b5774832b9..d1c8f4547c2 100644 --- a/_integration-test/test_run.py +++ b/_integration-test/test_run.py @@ -80,6 +80,14 @@ def test_initial_redirect(): assert initial_auth_redirect.url == f"{SENTRY_TEST_HOST}/auth/login/sentry/" +def test_asset_internal_rewrite(): + """Tests whether we correctly map `/_assets/*` to `/_static/dist/sentry` as + we don't have a CDN setup in self-hosted.""" + response = httpx.get(f"{SENTRY_TEST_HOST}/_assets/entrypoints/app.js") + assert response.status_code == 200 + assert response.headers["Content-Type"] == "text/javascript" + + def test_login(client_login): client, login_response = client_login parser = BeautifulSoup(login_response.text, "html.parser") diff --git a/nginx.conf b/nginx.conf index 32d9487f809..94d7964d58d 100644 --- a/nginx.conf +++ b/nginx.conf @@ -98,6 +98,10 @@ http { location / { proxy_pass http://sentry; } + location /_assets/ { + proxy_pass http://sentry/_static/dist/sentry/; + proxy_hide_header Content-Disposition; + } location /_static/ { proxy_pass http://sentry; proxy_hide_header Content-Disposition; From 92d7d836a33ba83c84780aad4cbf85d643261075 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sun, 22 Dec 2024 03:37:50 +0700 Subject: [PATCH 094/305] chore(relay): provide opt-in max_memory_percent config as workaround for failing healthcheck (#3486) See https://github.com/getsentry/self-hosted/issues/3330 --- relay/config.example.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/relay/config.example.yml b/relay/config.example.yml index 52e6630671f..f73e45acca8 100644 --- a/relay/config.example.yml +++ b/relay/config.example.yml @@ -11,3 +11,10 @@ processing: - {name: "message.max.bytes", value: 50000000} # 50MB redis: redis://redis:6379 geoip_path: "/geoip/GeoLite2-City.mmdb" + +# In some cases, relay might fail to find out the actual machine memory +# therefore it makes the healthcheck fail and events can't be submitted. +# As a workaround, uncomment the following line: +# +# health: +# max_memory_percent: 1.0 From aebe5542d40b2a296dbec46d5dc809ebcf66a761 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sun, 22 Dec 2024 03:59:30 +0700 Subject: [PATCH 095/305] chore: clearer message for errors-only mode (#3487) --- .env | 3 +++ sentry/sentry.conf.example.py | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.env b/.env index 58e11832a61..5688114306b 100644 --- a/.env +++ b/.env @@ -1,4 +1,7 @@ COMPOSE_PROJECT_NAME=sentry-self-hosted +# Set COMPOSE_PROFILES to "feature-complete" to enable all features +# To enable errors monitoring only, set COMPOSE_PROFILES=errors-only +# See https://develop.sentry.dev/self-hosted/experimental/errors-only/ COMPOSE_PROFILES=feature-complete SENTRY_EVENT_RETENTION_DAYS=90 # You can either use a port number or an IP:PORT combo for SENTRY_BIND diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 27f6ad02c2a..98e7a6c0fb3 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -72,6 +72,18 @@ def get_internal_network(): env("SENTRY_EVENT_RETENTION_DAYS", "90") ) +# Self-hosted Sentry infamously has a lot of Docker containers required to make +# all the features work. Oftentimes, users don't use the full feature set that +# requires all the containers. This is a way to enable only the error monitoring +# feature which also reduces the amount of containers required to run Sentry. +# +# To make Sentry work with all features, set `COMPOSE_PROFILES` to `feature-complete` +# in your `.env` file. To enable only the error monitoring feature, set +# `COMPOSE_PROFILES` to `errors-only`. +# +# See https://develop.sentry.dev/self-hosted/experimental/errors-only/ +SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" + ######### # Redis # ######### @@ -373,10 +385,6 @@ def get_internal_network(): # if you're using it directly like a CDN instead of using the loader script. JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle%s.min.js" - -# If you would like to use self-hosted Sentry with only errors enabled, please set this -SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" - ##################### # Insights Settings # ##################### From d8f64c6e8e4e63b50367a5927c844b172ecbfb54 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sat, 21 Dec 2024 21:02:30 +0000 Subject: [PATCH 096/305] release: 24.12.1 --- .env | 10 +++++----- CHANGELOG.md | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 5688114306b..c17453c64bb 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:24.12.1 +SNUBA_IMAGE=getsentry/snuba:24.12.1 +RELAY_IMAGE=getsentry/relay:24.12.1 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.12.1 +VROOM_IMAGE=getsentry/vroom:24.12.1 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index c08109c3f9e..56d9cfebee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 24.12.1 + +### Various fixes & improvements + +- chore: clearer message for errors-only mode (#3487) by @aldy505 +- chore(relay): provide opt-in max_memory_percent config as workaround for failing healthcheck (#3486) by @aldy505 +- fix(nginx): _assets should rewrite to _static/sentry/dist (#3483) by @BYK + ## 24.12.0 - No documented changes. From 4fa0833fd76537d3f7c09765f80e5ef82c9bc0f4 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sat, 21 Dec 2024 21:26:04 +0000 Subject: [PATCH 097/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index c17453c64bb..5688114306b 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:24.12.1 -SNUBA_IMAGE=getsentry/snuba:24.12.1 -RELAY_IMAGE=getsentry/relay:24.12.1 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:24.12.1 -VROOM_IMAGE=getsentry/vroom:24.12.1 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 0ca9311955a8b8d84d38b12385e2e252e2a73124 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Dec 2024 08:41:27 -0800 Subject: [PATCH 098/305] build(deps): bump actions/create-github-app-token from 1.11.0 to 1.11.1 (#3492) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1.11.0 to 1.11.1. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/5d869da34e18e7287c1daad50e0b8ea0f506ce69...c1a285145b9d317df6ced56c09f525b5c2b6f755) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7899952fc0f..38e929334f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 + uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From ad39dabdf08fc550d4ed8e79c2dd590ce76d0016 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 24 Dec 2024 01:32:17 +0300 Subject: [PATCH 099/305] ref(geoip): Remove geoipupdate from compose (#3490) `geoipupdate` is not used by any other service nor it is needed for any service to run. Moreover, it is a one-shot command, causing `docker compose up --wait` to fail when it exits with a non-zero status. This happens when one has not yet set up their credentials and they may choose to never do this. This PR removes `geoipupdate` from the `docker-compose.yml` file and moves the command directly into the geoip related script. One may run this whenever they want to update their GeoIP database. This PR needs an accompanying docs change. --- .github/workflows/test.yml | 1 + docker-compose.yml | 9 --------- install/geoip.sh | 2 +- install/set-up-and-migrate-database.sh | 8 +------- install/upgrade-clickhouse.sh | 20 +++----------------- install/upgrade-postgres.sh | 2 +- install/wrap-up.sh | 8 ++++---- sentry-admin.sh | 2 +- 8 files changed, 12 insertions(+), 40 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 291e78c7c8f..7660d437d3d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -134,6 +134,7 @@ jobs: - name: Integration Test run: | + docker compose up --wait if [ "${{ matrix.compose_version }}" = "v2.19.0" ]; then pytest --reruns 3 --cov --junitxml=junit.xml _integration-test/ --customizations=${{ matrix.customizations }} else diff --git a/docker-compose.yml b/docker-compose.yml index eeae00ee981..9d8ee5a9e4c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -207,15 +207,6 @@ services: interval: 10s timeout: 10s retries: 30 - geoipupdate: - image: "ghcr.io/maxmind/geoipupdate:v6.1.0" - # Override the entrypoint in order to avoid using envvars for config. - # Futz with settings so we can keep mmdb and conf in same dir on host - # (image looks for them in separate dirs by default). - entrypoint: - ["/usr/bin/geoipupdate", "-d", "/sentry", "-f", "/sentry/GeoIP.conf"] - volumes: - - "./geoip:/sentry" snuba-api: <<: *snuba_defaults # Kafka consumer responsible for feeding events into Clickhouse diff --git a/install/geoip.sh b/install/geoip.sh index 577b6ba5ca5..041db9b6833 100644 --- a/install/geoip.sh +++ b/install/geoip.sh @@ -21,7 +21,7 @@ install_geoip() { else echo "IP address geolocation is configured for updates." echo "Updating IP address geolocation database ... " - if ! $dcr geoipupdate; then + if ! docker run --rm -v "./geoip:/sentry" --entrypoint '/usr/bin/geoipupdate' "ghcr.io/maxmind/geoipupdate:v6.1.0" "-d" "/sentry" "-f" "/sentry/GeoIP.conf"; then result='Error' fi echo "$result updating IP address geolocation database." diff --git a/install/set-up-and-migrate-database.sh b/install/set-up-and-migrate-database.sh index 7bf74f40e95..770bfbdc61b 100644 --- a/install/set-up-and-migrate-database.sh +++ b/install/set-up-and-migrate-database.sh @@ -1,13 +1,7 @@ echo "${_group}Setting up / migrating database ..." # Fixes https://github.com/getsentry/self-hosted/issues/2758, where a migration fails due to indexing issue -$dc up -d postgres -# Wait for postgres -RETRIES=5 -until $dc exec postgres psql -U postgres -c "select 1" >/dev/null 2>&1 || [ $RETRIES -eq 0 ]; do - echo "Waiting for postgres server, $((RETRIES--)) remaining attempts..." - sleep 1 -done +$dc up --wait postgres os=$($dc exec postgres cat /etc/os-release | grep 'ID=debian') if [[ -z $os ]]; then diff --git a/install/upgrade-clickhouse.sh b/install/upgrade-clickhouse.sh index e9472384009..05e74bb00b9 100644 --- a/install/upgrade-clickhouse.sh +++ b/install/upgrade-clickhouse.sh @@ -1,33 +1,19 @@ echo "${_group}Upgrading Clickhouse ..." -function wait_for_clickhouse() { - # Wait for clickhouse - RETRIES=30 - until $dc ps clickhouse | grep 'healthy' || [ $RETRIES -eq 0 ]; do - echo "Waiting for clickhouse server, $((RETRIES--)) remaining attempts..." - sleep 1 - done -} - # First check to see if user is upgrading by checking for existing clickhouse volume if [[ -n "$(docker volume ls -q --filter name=sentry-clickhouse)" ]]; then # Start clickhouse if it is not already running - $dc up -d clickhouse - - # Wait for clickhouse - wait_for_clickhouse + $dc up --wait clickhouse # In order to get to 23.8, we need to first upgrade go from 21.8 -> 22.8 -> 23.3 -> 23.8 version=$($dc exec clickhouse clickhouse-client -q 'SELECT version()') if [[ "$version" == "21.8.13.1.altinitystable" || "$version" == "21.8.12.29.altinitydev.arm" ]]; then $dc down clickhouse $dcb --build-arg BASE_IMAGE=altinity/clickhouse-server:22.8.15.25.altinitystable clickhouse - $dc up -d clickhouse - wait_for_clickhouse + $dc up --wait clickhouse $dc down clickhouse $dcb --build-arg BASE_IMAGE=altinity/clickhouse-server:23.3.19.33.altinitystable clickhouse - $dc up -d clickhouse - wait_for_clickhouse + $dc up --wait clickhouse else echo "Detected clickhouse version $version. Skipping upgrades!" fi diff --git a/install/upgrade-postgres.sh b/install/upgrade-postgres.sh index 86b76646f33..fa66a0aa4ab 100644 --- a/install/upgrade-postgres.sh +++ b/install/upgrade-postgres.sh @@ -20,7 +20,7 @@ if [[ -n "$(docker volume ls -q --filter name=sentry-postgres)" && "$(docker run docker volume rm sentry-postgres-new echo "Re-indexing due to glibc change, this may take a while..." echo "Starting up new PostgreSQL version" - $dc up -d postgres + $dc up --wait postgres # Wait for postgres RETRIES=5 diff --git a/install/wrap-up.sh b/install/wrap-up.sh index 8840262f25d..c301c823f2b 100644 --- a/install/wrap-up.sh +++ b/install/wrap-up.sh @@ -2,7 +2,7 @@ if [[ "$MINIMIZE_DOWNTIME" ]]; then echo "${_group}Waiting for Sentry to start ..." # Start the whole setup, except nginx and relay. - $dc up -d --remove-orphans $($dc config --services | grep -v -E '^(nginx|relay)$') + $dc up --wait --remove-orphans $($dc config --services | grep -v -E '^(nginx|relay)$') $dc restart relay $dc exec -T nginx nginx -s reload @@ -10,7 +10,7 @@ if [[ "$MINIMIZE_DOWNTIME" ]]; then -c 'while [[ "$(wget -T 1 -q -O- http://web:9000/_health/)" != "ok" ]]; do sleep 0.5; done' # Make sure everything is up. This should only touch relay and nginx - $dc up -d + $dc up --wait echo "${_endgroup}" else @@ -20,9 +20,9 @@ else echo "You're all done! Run the following command to get Sentry running:" echo "" if [[ "${_ENV}" =~ ".env.custom" ]]; then - echo " $dc_base --env-file ${_ENV} up -d" + echo " $dc_base --env-file ${_ENV} up --wait" else - echo " $dc_base up -d" + echo " $dc_base up --wait" fi echo "" echo "-----------------------------------------------------------------" diff --git a/sentry-admin.sh b/sentry-admin.sh index d775e905e94..3db5f2ed044 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -22,7 +22,7 @@ on the host filesystem. Commands that write files should write them to the '/sen # Actual invocation that runs the command in the container. invocation() { - $dc run -v "$VOLUME_MAPPING" --rm -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 + $dcr --quiet-pull -v "$VOLUME_MAPPING" -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 } # Function to modify lines starting with `Usage: sentry` to say `Usage: ./sentry-admin.sh` instead. From 282410abff0a117e10822d9d84622356b5c3933e Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 24 Dec 2024 02:05:22 +0300 Subject: [PATCH 100/305] ref(snuba): Combine bootstrap & migrate for faster bootstrap (#3491) I think we split these actions in the past due to some lack of options for them to work together properly. Right now looks like `bootstrap` would automatically migrate and propagates the `force` flag. --- install/bootstrap-snuba.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/install/bootstrap-snuba.sh b/install/bootstrap-snuba.sh index 2952ed0b33c..489c4da0e17 100644 --- a/install/bootstrap-snuba.sh +++ b/install/bootstrap-snuba.sh @@ -1,6 +1,5 @@ echo "${_group}Bootstrapping and migrating Snuba ..." -$dcr snuba-api bootstrap --no-migrate --force -$dcr snuba-api migrations migrate --force +$dcr snuba-api bootstrap --force echo "${_endgroup}" From 1bb22c032d0baf7c4f6d935aa3559a5ccf91ba40 Mon Sep 17 00:00:00 2001 From: Mohamed Elneily Date: Sun, 29 Dec 2024 20:19:04 +0200 Subject: [PATCH 101/305] fix: Remove the extra space in the log file names (#3212) Update `_lib.sh` to remove the extra space in the log file name. This fixes the log files name not being included in `.gitinore` --- scripts/_lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/_lib.sh b/scripts/_lib.sh index 7ec51eecac1..a742f8acc51 100755 --- a/scripts/_lib.sh +++ b/scripts/_lib.sh @@ -76,7 +76,7 @@ MINIMIZE_DOWNTIME="${MINIMIZE_DOWNTIME:-}" STOP_TIMEOUT=60 # Save logs in order to send envelope to Sentry -log_file=sentry_"$cmd"_log-$(date +'%Y-%m-%d_%H-%M-%S').txt +log_file=sentry_"${cmd%% *}"_log-$(date +'%Y-%m-%d_%H-%M-%S').txt exec &> >(tee -a "$log_file") version="" From d5b49a41362f81caccbbbdc079d0904d352312ee Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 31 Dec 2024 01:37:53 +0300 Subject: [PATCH 102/305] ci: Cache postgres volume after first migration (#3488) This patch caches all DB volumes based on the sentry and snuba images to avoid doing the same migrations over and over for every test run. This shaved off a whole minute from "Install self-hosted" jobs (so ~20% speed increase). Left side: cached re-run -- Right side: no-cache initial run ![image](https://github.com/user-attachments/assets/55b923ea-d4c8-44bf-ba3e-0d5708781fd8) --- .github/workflows/test.yml | 83 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7660d437d3d..36a54676073 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,11 @@ on: pull_request: schedule: - cron: "0 0,12 * * *" + +concurrency: + group: ${{ github.ref_name || github.sha }} + cancel-in-progress: true + defaults: run: shell: bash @@ -66,9 +71,48 @@ jobs: sudo curl -L https://github.com/docker/compose/releases/download/v2.26.0/docker-compose-`uname -s`-`uname -m` -o "/usr/local/lib/docker/cli-plugins/docker-compose" sudo chmod +x "/usr/local/lib/docker/cli-plugins/docker-compose" + - name: Prepare Docker Volume Caching + id: cache_key + run: | + # Set permissions for docker volumes so we can cache and restore + sudo chmod o+x /var/lib/docker + sudo chmod -R o+rwx /var/lib/docker/volumes + source .env + SENTRY_IMAGE_SHA=$(docker buildx imagetools inspect $SENTRY_IMAGE --format "{{println .Manifest.Digest}}") + echo "SENTRY_IMAGE_SHA=$SENTRY_IMAGE_SHA" >> $GITHUB_OUTPUT + SNUBA_IMAGE_SHA=$(docker buildx imagetools inspect $SNUBA_IMAGE --format "{{println .Manifest.Digest}}") + echo "SNUBA_IMAGE_SHA=$SNUBA_IMAGE_SHA" >> $GITHUB_OUTPUT + + - name: Restore DB Volumes Cache + id: restore_cache + uses: actions/cache/restore@v4 + with: + key: db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }}-${{ steps.cache_key.outputs.SNUBA_IMAGE_SHA }} + restore-keys: | + db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }} + db-volumes-v4- + path: | + /var/lib/docker/volumes/sentry-postgres/_data + /var/lib/docker/volumes/sentry-clickhouse/_data + - name: Install ${{ env.LATEST_TAG }} run: ./install.sh + - name: Prepare Docker Volume Caching + run: | + # Set permissions for docker volumes so we can cache and restore + sudo chmod o+x /var/lib/docker + sudo chmod -R o+rx /var/lib/docker/volumes + + - name: Save DB Volumes Cache + if: steps.restore_cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + key: ${{ steps.restore_cache.outputs.cache-primary-key }} + path: | + /var/lib/docker/volumes/sentry-postgres/_data + /var/lib/docker/volumes/sentry-clickhouse/_data + - name: Checkout current ref uses: actions/checkout@v4 @@ -125,6 +169,30 @@ jobs: sudo curl -L https://github.com/docker/compose/releases/download/${{ matrix.compose_version }}/docker-compose-`uname -s`-`uname -m` -o "${{ matrix.compose_path }}/docker-compose" sudo chmod +x "${{ matrix.compose_path }}/docker-compose" + - name: Prepare Docker Volume Caching + id: cache_key + run: | + # Set permissions for docker volumes so we can cache and restore + sudo chmod o+x /var/lib/docker + sudo chmod -R o+rwx /var/lib/docker/volumes + source .env + SENTRY_IMAGE_SHA=$(docker buildx imagetools inspect $SENTRY_IMAGE --format "{{println .Manifest.Digest}}") + echo "SENTRY_IMAGE_SHA=$SENTRY_IMAGE_SHA" >> $GITHUB_OUTPUT + SNUBA_IMAGE_SHA=$(docker buildx imagetools inspect $SNUBA_IMAGE --format "{{println .Manifest.Digest}}") + echo "SNUBA_IMAGE_SHA=$SNUBA_IMAGE_SHA" >> $GITHUB_OUTPUT + + - name: Restore DB Volumes Cache + id: restore_cache + uses: actions/cache/restore@v4 + with: + key: db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }}-${{ steps.cache_key.outputs.SNUBA_IMAGE_SHA }} + restore-keys: | + db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }} + db-volumes-v4- + path: | + /var/lib/docker/volumes/sentry-postgres/_data + /var/lib/docker/volumes/sentry-clickhouse/_data + - name: Install self-hosted uses: nick-fields/retry@v3 with: @@ -132,6 +200,21 @@ jobs: max_attempts: 3 command: ./install.sh + - name: Prepare Docker Volume Caching + run: | + # Set permissions for docker volumes so we can cache and restore + sudo chmod o+x /var/lib/docker + sudo chmod -R o+rx /var/lib/docker/volumes + + - name: Save DB Volumes Cache + if: steps.restore_cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + key: ${{ steps.restore_cache.outputs.cache-primary-key }} + path: | + /var/lib/docker/volumes/sentry-postgres/_data + /var/lib/docker/volumes/sentry-clickhouse/_data + - name: Integration Test run: | docker compose up --wait From 8653327bc1f2097ad8666f6b87da31675f5b94f7 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Tue, 31 Dec 2024 10:53:14 -0800 Subject: [PATCH 103/305] chore: Remove everything zookeeper (#3499) --- install.sh | 1 - install/update-docker-volume-permissions.sh | 9 --------- install/wrap-up.sh | 5 ----- 3 files changed, 15 deletions(-) delete mode 100644 install/update-docker-volume-permissions.sh diff --git a/install.sh b/install.sh index e9460d36ceb..23726ce97fd 100755 --- a/install.sh +++ b/install.sh @@ -24,7 +24,6 @@ source install/check-minimum-requirements.sh # in order to determine whether or not the clickhouse version needs to be upgraded. source install/upgrade-clickhouse.sh source install/turn-things-off.sh -source install/update-docker-volume-permissions.sh source install/create-docker-volumes.sh source install/ensure-files-from-examples.sh source install/check-memcached-backend.sh diff --git a/install/update-docker-volume-permissions.sh b/install/update-docker-volume-permissions.sh deleted file mode 100644 index 8ac0be400c4..00000000000 --- a/install/update-docker-volume-permissions.sh +++ /dev/null @@ -1,9 +0,0 @@ -echo "${_group}Ensuring Kafka and Zookeeper volumes have correct permissions ..." - -# Only supporting platforms on linux x86 platforms and not apple silicon. I'm assuming that folks using apple silicon are doing it for dev purposes and it's difficult -# to change permissions of docker volumes since it is run in a VM. -if [[ -n "$(docker volume ls -q -f name=sentry-zookeeper)" && -n "$(docker volume ls -q -f name=sentry-kafka)" ]]; then - docker run --rm -v "sentry-zookeeper:/sentry-zookeeper-data" -v "sentry-kafka:/sentry-kafka-data" -v "${COMPOSE_PROJECT_NAME}_sentry-zookeeper-log:/sentry-zookeeper-log-data" busybox chmod -R a+w /sentry-zookeeper-data /sentry-kafka-data /sentry-zookeeper-log-data -fi - -echo "${_endgroup}" diff --git a/install/wrap-up.sh b/install/wrap-up.sh index c301c823f2b..dcc4e33c218 100644 --- a/install/wrap-up.sh +++ b/install/wrap-up.sh @@ -28,8 +28,3 @@ else echo "-----------------------------------------------------------------" echo "" fi - -# TODO(getsentry/self-hosted#2489) -if docker volume ls | grep -qw sentry-zookeeper; then - docker volume rm sentry-zookeeper -fi From 8c1653dc4a4b0b2b8c8fa81f668bcc52d9201f2b Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 1 Jan 2025 00:26:22 +0300 Subject: [PATCH 104/305] ci: Skip DB ops during install completely on cache hit (#3496) Follow up to #3488 A new record: 2m 8s for installing self-hosted: ![image](https://github.com/user-attachments/assets/7cc6409d-5388-49ba-ad87-b7a1e99c9acc) --- .github/workflows/test.yml | 39 +++++++++++++++++++----- install/set-up-and-migrate-database.sh | 41 ++++++++++++++------------ 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 36a54676073..79f8dc5a2ae 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -94,15 +94,24 @@ jobs: path: | /var/lib/docker/volumes/sentry-postgres/_data /var/lib/docker/volumes/sentry-clickhouse/_data + /var/lib/docker/volumes/sentry-kafka/_data - name: Install ${{ env.LATEST_TAG }} - run: ./install.sh + env: + SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} + run: | + # This is for the cache restore on Kafka to work in older releases + docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data + ./install.sh - name: Prepare Docker Volume Caching run: | # Set permissions for docker volumes so we can cache and restore sudo chmod o+x /var/lib/docker sudo chmod -R o+rx /var/lib/docker/volumes + # Set tar ownership for it to be able to read + # From: https://github.com/actions/toolkit/issues/946#issuecomment-1726311681 + sudo chown root /usr/bin/tar && sudo chmod u+s /usr/bin/tar - name: Save DB Volumes Cache if: steps.restore_cache.outputs.cache-hit != 'true' @@ -112,12 +121,22 @@ jobs: path: | /var/lib/docker/volumes/sentry-postgres/_data /var/lib/docker/volumes/sentry-clickhouse/_data + /var/lib/docker/volumes/sentry-kafka/_data - name: Checkout current ref uses: actions/checkout@v4 - name: Install current ref - run: ./install.sh + run: | + # This is for the cache restore on Kafka to work in older releases + docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data + ./install.sh + + - name: Inspect failure + if: failure() + run: | + docker compose ps + docker compose logs integration-test: if: github.repository_owner == 'getsentry' @@ -192,19 +211,24 @@ jobs: path: | /var/lib/docker/volumes/sentry-postgres/_data /var/lib/docker/volumes/sentry-clickhouse/_data + /var/lib/docker/volumes/sentry-kafka/_data - name: Install self-hosted - uses: nick-fields/retry@v3 - with: - timeout_minutes: 10 - max_attempts: 3 - command: ./install.sh + env: + SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} + run: | + # This is for the cache restore on Kafka to work in older releases + docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data + ./install.sh - name: Prepare Docker Volume Caching run: | # Set permissions for docker volumes so we can cache and restore sudo chmod o+x /var/lib/docker sudo chmod -R o+rx /var/lib/docker/volumes + # Set tar ownership for it to be able to read + # From: https://github.com/actions/toolkit/issues/946#issuecomment-1726311681 + sudo chown root /usr/bin/tar && sudo chmod u+s /usr/bin/tar - name: Save DB Volumes Cache if: steps.restore_cache.outputs.cache-hit != 'true' @@ -214,6 +238,7 @@ jobs: path: | /var/lib/docker/volumes/sentry-postgres/_data /var/lib/docker/volumes/sentry-clickhouse/_data + /var/lib/docker/volumes/sentry-kafka/_data - name: Integration Test run: | diff --git a/install/set-up-and-migrate-database.sh b/install/set-up-and-migrate-database.sh index 770bfbdc61b..a1cc8323e89 100644 --- a/install/set-up-and-migrate-database.sh +++ b/install/set-up-and-migrate-database.sh @@ -1,16 +1,17 @@ echo "${_group}Setting up / migrating database ..." -# Fixes https://github.com/getsentry/self-hosted/issues/2758, where a migration fails due to indexing issue -$dc up --wait postgres +if [[ -z "${SKIP_DB_MIGRATIONS:-}" ]]; then + # Fixes https://github.com/getsentry/self-hosted/issues/2758, where a migration fails due to indexing issue + $dc up --wait postgres -os=$($dc exec postgres cat /etc/os-release | grep 'ID=debian') -if [[ -z $os ]]; then - echo "Postgres image debian check failed, exiting..." - exit 1 -fi + os=$($dc exec postgres cat /etc/os-release | grep 'ID=debian') + if [[ -z $os ]]; then + echo "Postgres image debian check failed, exiting..." + exit 1 + fi -# Using django ORM to provide broader support for users with external databases -$dcr web shell -c " + # Using django ORM to provide broader support for users with external databases + $dcr web shell -c " from django.db import connection with connection.cursor() as cursor: @@ -18,16 +19,18 @@ with connection.cursor() as cursor: cursor.execute('DROP INDEX IF EXISTS sentry_groupedmessage_project_id_id_515aaa7e_uniq;') " -if [[ -n "${CI:-}" || "${SKIP_USER_CREATION:-0}" == 1 ]]; then - $dcr web upgrade --noinput --create-kafka-topics - echo "" - echo "Did not prompt for user creation. Run the following command to create one" - echo "yourself (recommended):" - echo "" - echo " $dc_base run --rm web createuser" - echo "" + if [[ -n "${CI:-}" || "${SKIP_USER_CREATION:-0}" == 1 ]]; then + $dcr web upgrade --noinput --create-kafka-topics + echo "" + echo "Did not prompt for user creation. Run the following command to create one" + echo "yourself (recommended):" + echo "" + echo " $dc_base run --rm web createuser" + echo "" + else + $dcr web upgrade --create-kafka-topics + fi else - $dcr web upgrade --create-kafka-topics + echo "Skipped DB migrations due to SKIP_DB_MIGRATIONS=$SKIP_DB_MIGRATIONS" fi - echo "${_endgroup}" From cb9e0ce5526fe59f07758ecbca4252c7a56a89c4 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 3 Jan 2025 00:36:33 +0300 Subject: [PATCH 105/305] ci: Only test on compose 2.26 w/ customizations (#3506) Docker Compose is much more robust nowadays compared to the past where we had to maintain tests for both v1 and v2 and then a specific version of v2. Hence, we are removing tests for the older versions of Docker Compose with this patch. We also remove the separate tests for customizations and w/o customizations as the one with customizations should cover the one without them anyway. This reduces the CI workload to 25% of what it was --- .github/workflows/test.yml | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 79f8dc5a2ae..cbea11a9311 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -141,19 +141,8 @@ jobs: integration-test: if: github.repository_owner == 'getsentry' runs-on: ubuntu-22.04 - name: integration test ${{ matrix.compose_version }} - customizations ${{ matrix.customizations }} - strategy: - fail-fast: false - matrix: - customizations: ["disabled", "enabled"] - compose_version: ["v2.19.0", "v2.26.0"] - include: - - compose_version: "v2.19.0" - compose_path: "/usr/local/lib/docker/cli-plugins" - - compose_version: "v2.26.0" - compose_path: "/usr/local/lib/docker/cli-plugins" + name: integration test env: - COMPOSE_PROJECT_NAME: self-hosted-${{ strategy.job-index }} REPORT_SELF_HOSTED_ISSUES: 0 SELF_HOSTED_TESTING_DSN: ${{ vars.SELF_HOSTED_TESTING_DSN }} steps: @@ -177,16 +166,19 @@ jobs: fi - name: Get Compose + env: + COMPOSE_PATH: /usr/local/lib/docker/cli-plugins + COMPOSE_VERSION: 'v2.26.0' run: | # Always remove `docker compose` support as that's the newer version # and comes installed by default nowadays. sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" # Docker Compose v1 is installed here, remove it sudo rm -f "/usr/local/bin/docker-compose" - sudo rm -f "${{ matrix.compose_path }}/docker-compose" - sudo mkdir -p "${{ matrix.compose_path }}" - sudo curl -L https://github.com/docker/compose/releases/download/${{ matrix.compose_version }}/docker-compose-`uname -s`-`uname -m` -o "${{ matrix.compose_path }}/docker-compose" - sudo chmod +x "${{ matrix.compose_path }}/docker-compose" + sudo rm -f "${{ env.COMPOSE_PATH }}/docker-compose" + sudo mkdir -p "${{ env.COMPOSE_PATH }}" + sudo curl -L https://github.com/docker/compose/releases/download/${{ env.COMPOSE_VERSION }}/docker-compose-`uname -s`-`uname -m` -o "${{ env.COMPOSE_PATH }}/docker-compose" + sudo chmod +x "${{ env.COMPOSE_PATH }}/docker-compose" - name: Prepare Docker Volume Caching id: cache_key @@ -243,11 +235,7 @@ jobs: - name: Integration Test run: | docker compose up --wait - if [ "${{ matrix.compose_version }}" = "v2.19.0" ]; then - pytest --reruns 3 --cov --junitxml=junit.xml _integration-test/ --customizations=${{ matrix.customizations }} - else - pytest --cov --junitxml=junit.xml _integration-test/ --customizations=${{ matrix.customizations }} - fi + pytest --cov --junitxml=junit.xml _integration-test/ --customizations=enabled - name: Inspect failure if: failure() From 63334cbcc23132e4d6832809ed399c75f48e4683 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 10 Jan 2025 20:51:11 +0000 Subject: [PATCH 106/305] ci: Move e2e test action into the repo (#3519) This is an initial transitionary patch before landing #3516. Once we land this, we will update users of the old action to use this one and remove that repo. Then land #3516 safely. Great thing is, with this patch and the subsequent update to getsentry/action-self-hosted-e2e-tests to use this one, all the repos would be using the Docker Volume caching we introduced in #3488. --- .github/workflows/test.yml | 117 +---------------------------- action.yaml | 149 +++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 113 deletions(-) create mode 100644 action.yaml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cbea11a9311..4dff1aa5fee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,21 +19,6 @@ defaults: run: shell: bash jobs: - e2e-test: - if: github.repository_owner == 'getsentry' - runs-on: ubuntu-22.04 - name: "Sentry self-hosted end-to-end tests" - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - path: self-hosted - - - name: End to end tests - uses: getsentry/action-self-hosted-e2e-tests@main - with: - project_name: self-hosted - unit-test: if: github.repository_owner == 'getsentry' runs-on: ubuntu-22.04 @@ -107,6 +92,7 @@ jobs: - name: Prepare Docker Volume Caching run: | # Set permissions for docker volumes so we can cache and restore + # We need these for the backup/restore test snapshotting too sudo chmod o+x /var/lib/docker sudo chmod -R o+rx /var/lib/docker/volumes # Set tar ownership for it to be able to read @@ -149,108 +135,13 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup dev environment - run: | - pip install -r requirements-dev.txt - echo "PY_COLORS=1" >> "$GITHUB_ENV" - ### pytest-sentry configuration ### - if [ "$GITHUB_REPOSITORY" = "getsentry/self-hosted" ]; then - echo "PYTEST_SENTRY_DSN=$SELF_HOSTED_TESTING_DSN" >> $GITHUB_ENV - echo "PYTEST_SENTRY_TRACES_SAMPLE_RATE=0" >> $GITHUB_ENV - - # This records failures on master to sentry in order to detect flakey tests, as it's - # expected that people have failing tests on their PRs - if [ "$GITHUB_REF" = "refs/heads/master" ]; then - echo "PYTEST_SENTRY_ALWAYS_REPORT=1" >> $GITHUB_ENV - fi - fi - - - name: Get Compose - env: - COMPOSE_PATH: /usr/local/lib/docker/cli-plugins - COMPOSE_VERSION: 'v2.26.0' - run: | - # Always remove `docker compose` support as that's the newer version - # and comes installed by default nowadays. - sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" - # Docker Compose v1 is installed here, remove it - sudo rm -f "/usr/local/bin/docker-compose" - sudo rm -f "${{ env.COMPOSE_PATH }}/docker-compose" - sudo mkdir -p "${{ env.COMPOSE_PATH }}" - sudo curl -L https://github.com/docker/compose/releases/download/${{ env.COMPOSE_VERSION }}/docker-compose-`uname -s`-`uname -m` -o "${{ env.COMPOSE_PATH }}/docker-compose" - sudo chmod +x "${{ env.COMPOSE_PATH }}/docker-compose" - - - name: Prepare Docker Volume Caching - id: cache_key - run: | - # Set permissions for docker volumes so we can cache and restore - sudo chmod o+x /var/lib/docker - sudo chmod -R o+rwx /var/lib/docker/volumes - source .env - SENTRY_IMAGE_SHA=$(docker buildx imagetools inspect $SENTRY_IMAGE --format "{{println .Manifest.Digest}}") - echo "SENTRY_IMAGE_SHA=$SENTRY_IMAGE_SHA" >> $GITHUB_OUTPUT - SNUBA_IMAGE_SHA=$(docker buildx imagetools inspect $SNUBA_IMAGE --format "{{println .Manifest.Digest}}") - echo "SNUBA_IMAGE_SHA=$SNUBA_IMAGE_SHA" >> $GITHUB_OUTPUT - - - name: Restore DB Volumes Cache - id: restore_cache - uses: actions/cache/restore@v4 - with: - key: db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }}-${{ steps.cache_key.outputs.SNUBA_IMAGE_SHA }} - restore-keys: | - db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }} - db-volumes-v4- - path: | - /var/lib/docker/volumes/sentry-postgres/_data - /var/lib/docker/volumes/sentry-clickhouse/_data - /var/lib/docker/volumes/sentry-kafka/_data - - - name: Install self-hosted - env: - SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} - run: | - # This is for the cache restore on Kafka to work in older releases - docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data - ./install.sh - - - name: Prepare Docker Volume Caching - run: | - # Set permissions for docker volumes so we can cache and restore - sudo chmod o+x /var/lib/docker - sudo chmod -R o+rx /var/lib/docker/volumes - # Set tar ownership for it to be able to read - # From: https://github.com/actions/toolkit/issues/946#issuecomment-1726311681 - sudo chown root /usr/bin/tar && sudo chmod u+s /usr/bin/tar - - - name: Save DB Volumes Cache - if: steps.restore_cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 + - name: Use action from local checkout + uses: './' with: - key: ${{ steps.restore_cache.outputs.cache-primary-key }} - path: | - /var/lib/docker/volumes/sentry-postgres/_data - /var/lib/docker/volumes/sentry-clickhouse/_data - /var/lib/docker/volumes/sentry-kafka/_data - - - name: Integration Test - run: | - docker compose up --wait - pytest --cov --junitxml=junit.xml _integration-test/ --customizations=enabled + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - name: Inspect failure if: failure() run: | docker compose ps docker compose logs - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - slug: getsentry/self-hosted - - - name: Upload test results to Codecov - if: ${{ !cancelled() }} - uses: codecov/test-results-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} diff --git a/action.yaml b/action.yaml new file mode 100644 index 00000000000..537be8c8260 --- /dev/null +++ b/action.yaml @@ -0,0 +1,149 @@ +name: "Sentry self-hosted end-to-end tests" +inputs: + project_name: + required: false + description: "e.g. snuba, sentry, relay, self-hosted" + image_url: + required: false + description: "The URL to the built relay, snuba, sentry image to test against." + CODECOV_TOKEN: + required: false + description: "The Codecov token to upload coverage." + +runs: + using: "composite" + steps: + - name: Go into self-hosted directory + shell: bash + run: cd ${{ github.action_path }} + + - name: Configure to use the test image + if: inputs.project_name && inputs.image_url + shell: bash + run: | + image_var=$(echo ${{ inputs.project_name }}_IMAGE | tr '[:lower:]' '[:upper:]') + echo "${image_var}=${{ inputs.image_url }}" >> $GITHUB_ENV + + - name: Setup dev environment + shell: bash + run: | + pip install -r requirements-dev.txt + echo "PY_COLORS=1" >> "$GITHUB_ENV" + ### pytest-sentry configuration ### + if [ "$GITHUB_REPOSITORY" = "getsentry/self-hosted" ]; then + echo "PYTEST_SENTRY_DSN=$SELF_HOSTED_TESTING_DSN" >> $GITHUB_ENV + echo "PYTEST_SENTRY_TRACES_SAMPLE_RATE=0" >> $GITHUB_ENV + + # This records failures on master to sentry in order to detect flakey tests, as it's + # expected that people have failing tests on their PRs + if [ "$GITHUB_REF" = "refs/heads/master" ]; then + echo "PYTEST_SENTRY_ALWAYS_REPORT=1" >> $GITHUB_ENV + fi + fi + + - name: Get Compose + env: + COMPOSE_PATH: /usr/local/lib/docker/cli-plugins + COMPOSE_VERSION: "v2.26.0" + shell: bash + run: | + # Always remove `docker compose` support as that's the newer version + # and comes installed by default nowadays. + sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" + # Docker Compose v1 is installed here, remove it + sudo rm -f "/usr/local/bin/docker-compose" + sudo rm -f "${{ env.COMPOSE_PATH }}/docker-compose" + sudo mkdir -p "${{ env.COMPOSE_PATH }}" + sudo curl -L https://github.com/docker/compose/releases/download/${{ env.COMPOSE_VERSION }}/docker-compose-`uname -s`-`uname -m` -o "${{ env.COMPOSE_PATH }}/docker-compose" + sudo chmod +x "${{ env.COMPOSE_PATH }}/docker-compose" + + - name: Prepare Docker Volume Caching + id: cache_key + shell: bash + run: | + # Set permissions for docker volumes so we can cache and restore + sudo chmod o+x /var/lib/docker + sudo chmod -R o+rwx /var/lib/docker/volumes + source .env + SENTRY_IMAGE_SHA=$(docker buildx imagetools inspect $SENTRY_IMAGE --format "{{println .Manifest.Digest}}") + echo "SENTRY_IMAGE_SHA=$SENTRY_IMAGE_SHA" >> $GITHUB_OUTPUT + SNUBA_IMAGE_SHA=$(docker buildx imagetools inspect $SNUBA_IMAGE --format "{{println .Manifest.Digest}}") + echo "SNUBA_IMAGE_SHA=$SNUBA_IMAGE_SHA" >> $GITHUB_OUTPUT + + - name: Restore DB Volumes Cache + id: restore_cache + uses: actions/cache/restore@v4 + with: + key: db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }}-${{ steps.cache_key.outputs.SNUBA_IMAGE_SHA }} + restore-keys: | + db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }} + db-volumes-v4- + path: | + /var/lib/docker/volumes/sentry-postgres/_data + /var/lib/docker/volumes/sentry-clickhouse/_data + /var/lib/docker/volumes/sentry-kafka/_data + + - name: Install self-hosted + env: + SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} + shell: bash + run: | + # This is for the cache restore on Kafka to work in older releases + docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data + # Add some customizations to test that path + cat <> sentry/enhance-image.sh + #!/bin/bash + touch /created-by-enhance-image + apt-get update + apt-get install -y gcc libsasl2-dev python-dev-is-python3 libldap2-dev libssl-dev + EOT + chmod 755 sentry/enhance-image.sh + echo "python-ldap" > sentry/requirements.txt + + ./install.sh --no-report-self-hosted-issues --skip-commit-check + + - name: Prepare Docker Volume Caching + shell: bash + run: | + # Set permissions for docker volumes so we can cache and restore + # We need these for the backup/restore test snapshotting too + sudo chmod o+x /var/lib/docker + sudo chmod -R o+rx /var/lib/docker/volumes + # Set tar ownership for it to be able to read + # From: https://github.com/actions/toolkit/issues/946#issuecomment-1726311681 + sudo chown root /usr/bin/tar && sudo chmod u+s /usr/bin/tar + sudo chown root /usr/bin/rsync && sudo chmod u+s /usr/bin/rsync + + - name: Save DB Volumes Cache + if: steps.restore_cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + key: ${{ steps.restore_cache.outputs.cache-primary-key }} + path: | + /var/lib/docker/volumes/sentry-postgres/_data + /var/lib/docker/volumes/sentry-clickhouse/_data + /var/lib/docker/volumes/sentry-kafka/_data + + - name: Integration Test + shell: bash + run: | + rsync -aW --no-compress --mkpath \ + /var/lib/docker/volumes/sentry-postgres \ + /var/lib/docker/volumes/sentry-clickhouse \ + /var/lib/docker/volumes/sentry-kafka \ + "$RUNNER_TEMP/volumes/" + docker compose up --wait + TEST_CUSTOMIZATIONS=enabled pytest -x --cov --junitxml=junit.xml _integration-test/ + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + if: inputs.CODECOV_TOKEN + with: + token: ${{ inputs.CODECOV_TOKEN }} + slug: getsentry/self-hosted + + - name: Upload test results to Codecov + if: inputs.CODECOV_TOKEN && !cancelled() + uses: codecov/test-results-action@v1 + with: + token: ${{ inputs.CODECOV_TOKEN }} From b948b10843db317cf6649cf5069aeae01b58f2c2 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 10 Jan 2025 22:08:13 +0000 Subject: [PATCH 107/305] fix: Fix the new e2e action to be portable (#3520) See errors on getsentry/snuba#6746 --- action.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/action.yaml b/action.yaml index 537be8c8260..6ca973e98c4 100644 --- a/action.yaml +++ b/action.yaml @@ -13,20 +13,17 @@ inputs: runs: using: "composite" steps: - - name: Go into self-hosted directory - shell: bash - run: cd ${{ github.action_path }} - - name: Configure to use the test image if: inputs.project_name && inputs.image_url shell: bash run: | image_var=$(echo ${{ inputs.project_name }}_IMAGE | tr '[:lower:]' '[:upper:]') - echo "${image_var}=${{ inputs.image_url }}" >> $GITHUB_ENV + echo "${image_var}=${{ inputs.image_url }}" >> ${{ github.action_path }}/.env - name: Setup dev environment shell: bash run: | + cd ${{ github.action_path }} pip install -r requirements-dev.txt echo "PY_COLORS=1" >> "$GITHUB_ENV" ### pytest-sentry configuration ### @@ -64,7 +61,7 @@ runs: # Set permissions for docker volumes so we can cache and restore sudo chmod o+x /var/lib/docker sudo chmod -R o+rwx /var/lib/docker/volumes - source .env + source ${{ github.action_path }}/.env SENTRY_IMAGE_SHA=$(docker buildx imagetools inspect $SENTRY_IMAGE --format "{{println .Manifest.Digest}}") echo "SENTRY_IMAGE_SHA=$SENTRY_IMAGE_SHA" >> $GITHUB_OUTPUT SNUBA_IMAGE_SHA=$(docker buildx imagetools inspect $SNUBA_IMAGE --format "{{println .Manifest.Digest}}") @@ -88,6 +85,7 @@ runs: SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} shell: bash run: | + cd ${{ github.action_path }} # This is for the cache restore on Kafka to work in older releases docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data # Add some customizations to test that path @@ -132,6 +130,7 @@ runs: /var/lib/docker/volumes/sentry-clickhouse \ /var/lib/docker/volumes/sentry-kafka \ "$RUNNER_TEMP/volumes/" + cd ${{ github.action_path }} docker compose up --wait TEST_CUSTOMIZATIONS=enabled pytest -x --cov --junitxml=junit.xml _integration-test/ @@ -139,6 +138,7 @@ runs: uses: codecov/codecov-action@v5 if: inputs.CODECOV_TOKEN with: + directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} slug: getsentry/self-hosted @@ -146,4 +146,5 @@ runs: if: inputs.CODECOV_TOKEN && !cancelled() uses: codecov/test-results-action@v1 with: + directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} From f97a5e2390455d7f5b368cb394730c1206394660 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 11 Jan 2025 21:59:13 +0000 Subject: [PATCH 108/305] ci: Faster and smarter backup/restore tests (#3516) From ``` ================== 11 passed, 4 warnings in 762.35s (0:12:42) ================== ``` to ``` ================== 11 passed, 4 warnings in 343.58s (0:05:43) ================== ``` --- _integration-test/conftest.py | 43 +-------------------------- _integration-test/test_backup.py | 50 ++++++++++++++++++++++++-------- _integration-test/test_run.py | 15 ++++++---- action.yaml | 2 +- install/bootstrap-snuba.sh | 6 +++- 5 files changed, 55 insertions(+), 61 deletions(-) diff --git a/_integration-test/conftest.py b/_integration-test/conftest.py index b36097d6056..e80cef95e6a 100644 --- a/_integration-test/conftest.py +++ b/_integration-test/conftest.py @@ -1,58 +1,17 @@ import os +from os.path import join import subprocess -import time -import httpx import pytest SENTRY_CONFIG_PY = "sentry/sentry.conf.py" SENTRY_TEST_HOST = os.getenv("SENTRY_TEST_HOST", "http://localhost:9000") TEST_USER = "test@example.com" TEST_PASS = "test123TEST" -TIMEOUT_SECONDS = 60 - - -def pytest_addoption(parser): - parser.addoption("--customizations", default="disabled") @pytest.fixture(scope="session", autouse=True) def configure_self_hosted_environment(request): - subprocess.run( - ["docker", "compose", "--ansi", "never", "up", "-d"], - check=True, - capture_output=True, - ) - for i in range(TIMEOUT_SECONDS): - try: - response = httpx.get(SENTRY_TEST_HOST, follow_redirects=True) - except httpx.RequestError: - time.sleep(1) - else: - if response.status_code == 200: - break - else: - raise AssertionError("timeout waiting for self-hosted to come up") - - if request.config.getoption("--customizations") == "enabled": - os.environ["TEST_CUSTOMIZATIONS"] = "enabled" - script_content = """\ -#!/bin/bash -touch /created-by-enhance-image -apt-get update -apt-get install -y gcc libsasl2-dev python-dev-is-python3 libldap2-dev libssl-dev -""" - - with open("sentry/enhance-image.sh", "w") as script_file: - script_file.write(script_content) - # Set executable permissions for the shell script - os.chmod("sentry/enhance-image.sh", 0o755) - - # Write content to the requirements.txt file - with open("sentry/requirements.txt", "w") as req_file: - req_file.write("python-ldap\n") - os.environ["MINIMIZE_DOWNTIME"] = "1" - subprocess.run(["./install.sh"], check=True, capture_output=True) # Create test user subprocess.run( [ diff --git a/_integration-test/test_backup.py b/_integration-test/test_backup.py index 41c099741a2..b73e0cfb163 100644 --- a/_integration-test/test_backup.py +++ b/_integration-test/test_backup.py @@ -1,4 +1,5 @@ import os +from os.path import join import subprocess @@ -20,7 +21,7 @@ def test_sentry_admin(setup_backup_restore_env_variables): def test_backup(setup_backup_restore_env_variables): - # Docker was giving me permissioning issues when trying to create this file and write to it even after giving read + write access + # Docker was giving me permission issues when trying to create this file and write to it even after giving read + write access # to group and owner. Instead, try creating the empty file and then give everyone write access to the backup file file_path = os.path.join(os.getcwd(), "sentry", "backup.json") sentry_admin_sh = os.path.join(os.getcwd(), "sentry-admin.sh") @@ -42,21 +43,46 @@ def test_backup(setup_backup_restore_env_variables): def test_import(setup_backup_restore_env_variables): # Bring postgres down and recreate the docker volume + subprocess.run(["docker", "compose", "--ansi", "never", "down"], check=True) + # We reset all DB-related volumes here and not just Postgres although the backups + # are only for Postgres. The reason is to get a "clean slate" as we need the Kafka + # and Clickhouse volumes to be back to their initial state as well ( without any events) + # We cannot just rm and create them as they still need migrations. + for name in ("postgres", "clickhouse", "kafka"): + subprocess.run(["docker", "volume", "rm", f"sentry-{name}"], check=True) + subprocess.run( + [ + "rsync", + "-aW", + "--no-compress", + "--mkpath", + join(os.environ["RUNNER_TEMP"], "volumes", f"sentry-{name}", ""), + f"/var/lib/docker/volumes/sentry-{name}/", + ], + check=True, + capture_output=True, + ) + subprocess.run(["docker", "volume", "create", f"sentry-{name}"], check=True) + subprocess.run( - ["docker", "compose", "--ansi", "never", "stop", "postgres"], check=True - ) - subprocess.run( - ["docker", "compose", "--ansi", "never", "rm", "-f", "-v", "postgres"], - check=True, - ) - subprocess.run(["docker", "volume", "rm", "sentry-postgres"], check=True) - subprocess.run(["docker", "volume", "create", "--name=sentry-postgres"], check=True) - subprocess.run( - ["docker", "compose", "--ansi", "never", "run", "web", "upgrade", "--noinput"], + [ + "docker", + "run", + "--rm", + "-v", + "sentry-kafka:/data", + "busybox", + "chown", + "-R", + "1000:1000", + "/data", + ], check=True, + capture_output=True, ) + subprocess.run( - ["docker", "compose", "--ansi", "never", "up", "-d"], + ["docker", "compose", "--ansi", "never", "up", "--wait"], check=True, capture_output=True, ) diff --git a/_integration-test/test_run.py b/_integration-test/test_run.py index d1c8f4547c2..110de083855 100644 --- a/_integration-test/test_run.py +++ b/_integration-test/test_run.py @@ -326,7 +326,15 @@ def test_custom_certificate_authorities(): ) subprocess.run( - ["docker", "compose", "--ansi", "never", "up", "-d", "fixture-custom-ca-roots"], + [ + "docker", + "compose", + "--ansi", + "never", + "up", + "--wait", + "fixture-custom-ca-roots", + ], check=True, ) subprocess.run( @@ -448,7 +456,4 @@ def test_customizations(): ] for command in commands: result = subprocess.run(command, check=False) - if os.getenv("TEST_CUSTOMIZATIONS", "disabled") == "enabled": - assert result.returncode == 0 - else: - assert result.returncode != 0 + assert result.returncode == 0 diff --git a/action.yaml b/action.yaml index 6ca973e98c4..24baf35d6b4 100644 --- a/action.yaml +++ b/action.yaml @@ -132,7 +132,7 @@ runs: "$RUNNER_TEMP/volumes/" cd ${{ github.action_path }} docker compose up --wait - TEST_CUSTOMIZATIONS=enabled pytest -x --cov --junitxml=junit.xml _integration-test/ + pytest -x --cov --junitxml=junit.xml _integration-test/ - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 diff --git a/install/bootstrap-snuba.sh b/install/bootstrap-snuba.sh index 489c4da0e17..20666302ade 100644 --- a/install/bootstrap-snuba.sh +++ b/install/bootstrap-snuba.sh @@ -1,5 +1,9 @@ echo "${_group}Bootstrapping and migrating Snuba ..." -$dcr snuba-api bootstrap --force +if [[ -z "${SKIP_DB_MIGRATIONS:-}" ]]; then + $dcr snuba-api bootstrap --force +else + echo "Skipped DB migrations due to SKIP_DB_MIGRATIONS=$SKIP_DB_MIGRATIONS" +fi echo "${_endgroup}" From b439c67e17120c9fdd20aec5250a6357f78bd6c0 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 13 Jan 2025 03:00:52 +0700 Subject: [PATCH 109/305] docs: include regular env file on wrap-up (#3523) --- install/wrap-up.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/wrap-up.sh b/install/wrap-up.sh index dcc4e33c218..6f242284fe6 100644 --- a/install/wrap-up.sh +++ b/install/wrap-up.sh @@ -20,7 +20,7 @@ else echo "You're all done! Run the following command to get Sentry running:" echo "" if [[ "${_ENV}" =~ ".env.custom" ]]; then - echo " $dc_base --env-file ${_ENV} up --wait" + echo " $dc_base --env-file .env --env-file ${_ENV} up --wait" else echo " $dc_base up --wait" fi From d807ca4277a80d0ead633b0f7b8fb120027024f5 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Mon, 13 Jan 2025 20:35:31 +0000 Subject: [PATCH 110/305] ci: Less volatile cache keys (#3522) Instead of using direct image hashes, only use hashes from migrations folders for each respective image for cache key generation. Should increase cache hit rate significantly as we don't have migrations much. Also swaps the key order from `sentry-snuba` to `snuba-senry` assuming Snuba has less frequent migration additions. --- .github/workflows/test.yml | 14 +++++++------- action.yaml | 16 +++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4dff1aa5fee..ed1547909a3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,19 +63,19 @@ jobs: sudo chmod o+x /var/lib/docker sudo chmod -R o+rwx /var/lib/docker/volumes source .env - SENTRY_IMAGE_SHA=$(docker buildx imagetools inspect $SENTRY_IMAGE --format "{{println .Manifest.Digest}}") - echo "SENTRY_IMAGE_SHA=$SENTRY_IMAGE_SHA" >> $GITHUB_OUTPUT - SNUBA_IMAGE_SHA=$(docker buildx imagetools inspect $SNUBA_IMAGE --format "{{println .Manifest.Digest}}") - echo "SNUBA_IMAGE_SHA=$SNUBA_IMAGE_SHA" >> $GITHUB_OUTPUT + SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c 'ls -Rv1rpq src/sentry/migrations/' | md5sum | cut -d ' ' -f 1) + echo "SENTRY_MIGRATIONS_MD5=$SENTRY_MIGRATIONS_MD5" >> $GITHUB_OUTPUT + SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c 'ls -Rv1rpq snuba/snuba_migrations/**/*.py' | md5sum | cut -d ' ' -f 1) + echo "SNUBA_MIGRATIONS_MD5=$SNUBA_MIGRATIONS_MD5" >> $GITHUB_OUTPUT - name: Restore DB Volumes Cache id: restore_cache uses: actions/cache/restore@v4 with: - key: db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }}-${{ steps.cache_key.outputs.SNUBA_IMAGE_SHA }} + key: db-volumes-v5-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} restore-keys: | - db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }} - db-volumes-v4- + db-volumes-v5-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + db-volumes-v5- path: | /var/lib/docker/volumes/sentry-postgres/_data /var/lib/docker/volumes/sentry-clickhouse/_data diff --git a/action.yaml b/action.yaml index 24baf35d6b4..fe2cc073ec4 100644 --- a/action.yaml +++ b/action.yaml @@ -62,19 +62,21 @@ runs: sudo chmod o+x /var/lib/docker sudo chmod -R o+rwx /var/lib/docker/volumes source ${{ github.action_path }}/.env - SENTRY_IMAGE_SHA=$(docker buildx imagetools inspect $SENTRY_IMAGE --format "{{println .Manifest.Digest}}") - echo "SENTRY_IMAGE_SHA=$SENTRY_IMAGE_SHA" >> $GITHUB_OUTPUT - SNUBA_IMAGE_SHA=$(docker buildx imagetools inspect $SNUBA_IMAGE --format "{{println .Manifest.Digest}}") - echo "SNUBA_IMAGE_SHA=$SNUBA_IMAGE_SHA" >> $GITHUB_OUTPUT + # See https://explainshell.com/explain?cmd=ls%20-Rv1rpq + # for that long `ls` command + SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c 'ls -Rv1rpq src/sentry/migrations/' | md5sum | cut -d ' ' -f 1) + echo "SENTRY_MIGRATIONS_MD5=$SENTRY_MIGRATIONS_MD5" >> $GITHUB_OUTPUT + SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c 'ls -Rv1rpq snuba/snuba_migrations/**/*.py' | md5sum | cut -d ' ' -f 1) + echo "SNUBA_MIGRATIONS_MD5=$SNUBA_MIGRATIONS_MD5" >> $GITHUB_OUTPUT - name: Restore DB Volumes Cache id: restore_cache uses: actions/cache/restore@v4 with: - key: db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }}-${{ steps.cache_key.outputs.SNUBA_IMAGE_SHA }} + key: db-volumes-v5-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} restore-keys: | - db-volumes-v4-${{ steps.cache_key.outputs.SENTRY_IMAGE_SHA }} - db-volumes-v4- + db-volumes-v5-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + db-volumes-v5- path: | /var/lib/docker/volumes/sentry-postgres/_data /var/lib/docker/volumes/sentry-clickhouse/_data From f21b16d0ec6fb2d956dbd4d6b06fba0fdefbbc79 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 14 Jan 2025 22:09:11 +0000 Subject: [PATCH 111/305] ci: Use generic Docker volume cache action (#3524) See https://github.com/BYK/docker-volume-cache-action --- .github/workflows/test.yml | 47 +++++++++++++--------------------- action.yaml | 48 ++++++++++++----------------------- install/upgrade-clickhouse.sh | 2 +- 3 files changed, 35 insertions(+), 62 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ed1547909a3..3e471c84baa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,12 +56,9 @@ jobs: sudo curl -L https://github.com/docker/compose/releases/download/v2.26.0/docker-compose-`uname -s`-`uname -m` -o "/usr/local/lib/docker/cli-plugins/docker-compose" sudo chmod +x "/usr/local/lib/docker/cli-plugins/docker-compose" - - name: Prepare Docker Volume Caching + - name: Compute Docker Volume Cache Key id: cache_key run: | - # Set permissions for docker volumes so we can cache and restore - sudo chmod o+x /var/lib/docker - sudo chmod -R o+rwx /var/lib/docker/volumes source .env SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c 'ls -Rv1rpq src/sentry/migrations/' | md5sum | cut -d ' ' -f 1) echo "SENTRY_MIGRATIONS_MD5=$SENTRY_MIGRATIONS_MD5" >> $GITHUB_OUTPUT @@ -70,44 +67,36 @@ jobs: - name: Restore DB Volumes Cache id: restore_cache - uses: actions/cache/restore@v4 + uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-v5-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} + key: db-volumes-v6-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} restore-keys: | - db-volumes-v5-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} - db-volumes-v5- - path: | - /var/lib/docker/volumes/sentry-postgres/_data - /var/lib/docker/volumes/sentry-clickhouse/_data - /var/lib/docker/volumes/sentry-kafka/_data + db-volumes-v6-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + db-volumes-v6- + volumes: | + sentry-postgres + sentry-clickhouse + sentry-kafka - name: Install ${{ env.LATEST_TAG }} env: SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} run: | - # This is for the cache restore on Kafka to work in older releases - docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data + # This is to compensate for a bug in upgrade-clickhouse where + # if we have sentry-clickhouse volume without the rest, it fails + # We may get sentry-clickhouse from the cache step above + source install/create-docker-volumes.sh ./install.sh - - name: Prepare Docker Volume Caching - run: | - # Set permissions for docker volumes so we can cache and restore - # We need these for the backup/restore test snapshotting too - sudo chmod o+x /var/lib/docker - sudo chmod -R o+rx /var/lib/docker/volumes - # Set tar ownership for it to be able to read - # From: https://github.com/actions/toolkit/issues/946#issuecomment-1726311681 - sudo chown root /usr/bin/tar && sudo chmod u+s /usr/bin/tar - - name: Save DB Volumes Cache if: steps.restore_cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 + uses: BYK/docker-volume-cache-action/save@be89365902126f508dcae387a32ec3712df6b1cd with: key: ${{ steps.restore_cache.outputs.cache-primary-key }} - path: | - /var/lib/docker/volumes/sentry-postgres/_data - /var/lib/docker/volumes/sentry-clickhouse/_data - /var/lib/docker/volumes/sentry-kafka/_data + volumes: | + sentry-postgres + sentry-clickhouse + sentry-kafka - name: Checkout current ref uses: actions/checkout@v4 diff --git a/action.yaml b/action.yaml index fe2cc073ec4..ec5897f0a27 100644 --- a/action.yaml +++ b/action.yaml @@ -18,7 +18,7 @@ runs: shell: bash run: | image_var=$(echo ${{ inputs.project_name }}_IMAGE | tr '[:lower:]' '[:upper:]') - echo "${image_var}=${{ inputs.image_url }}" >> ${{ github.action_path }}/.env + echo "${image_var}=${{ inputs.image_url }}" >> ${{ github.action_path }}.env - name: Setup dev environment shell: bash @@ -54,13 +54,10 @@ runs: sudo curl -L https://github.com/docker/compose/releases/download/${{ env.COMPOSE_VERSION }}/docker-compose-`uname -s`-`uname -m` -o "${{ env.COMPOSE_PATH }}/docker-compose" sudo chmod +x "${{ env.COMPOSE_PATH }}/docker-compose" - - name: Prepare Docker Volume Caching + - name: Compute Docker Volume Cache Key id: cache_key shell: bash run: | - # Set permissions for docker volumes so we can cache and restore - sudo chmod o+x /var/lib/docker - sudo chmod -R o+rwx /var/lib/docker/volumes source ${{ github.action_path }}/.env # See https://explainshell.com/explain?cmd=ls%20-Rv1rpq # for that long `ls` command @@ -71,16 +68,16 @@ runs: - name: Restore DB Volumes Cache id: restore_cache - uses: actions/cache/restore@v4 + uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-v5-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} + key: db-volumes-v6-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} restore-keys: | - db-volumes-v5-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} - db-volumes-v5- - path: | - /var/lib/docker/volumes/sentry-postgres/_data - /var/lib/docker/volumes/sentry-clickhouse/_data - /var/lib/docker/volumes/sentry-kafka/_data + db-volumes-v6-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + db-volumes-v6- + volumes: | + sentry-postgres + sentry-clickhouse + sentry-kafka - name: Install self-hosted env: @@ -88,8 +85,6 @@ runs: shell: bash run: | cd ${{ github.action_path }} - # This is for the cache restore on Kafka to work in older releases - docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data # Add some customizations to test that path cat <> sentry/enhance-image.sh #!/bin/bash @@ -102,31 +97,20 @@ runs: ./install.sh --no-report-self-hosted-issues --skip-commit-check - - name: Prepare Docker Volume Caching - shell: bash - run: | - # Set permissions for docker volumes so we can cache and restore - # We need these for the backup/restore test snapshotting too - sudo chmod o+x /var/lib/docker - sudo chmod -R o+rx /var/lib/docker/volumes - # Set tar ownership for it to be able to read - # From: https://github.com/actions/toolkit/issues/946#issuecomment-1726311681 - sudo chown root /usr/bin/tar && sudo chmod u+s /usr/bin/tar - sudo chown root /usr/bin/rsync && sudo chmod u+s /usr/bin/rsync - - name: Save DB Volumes Cache if: steps.restore_cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 + uses: BYK/docker-volume-cache-action/save@be89365902126f508dcae387a32ec3712df6b1cd with: key: ${{ steps.restore_cache.outputs.cache-primary-key }} - path: | - /var/lib/docker/volumes/sentry-postgres/_data - /var/lib/docker/volumes/sentry-clickhouse/_data - /var/lib/docker/volumes/sentry-kafka/_data + volumes: | + sentry-postgres + sentry-clickhouse + sentry-kafka - name: Integration Test shell: bash run: | + sudo chown root /usr/bin/rsync && sudo chmod u+s /usr/bin/rsync rsync -aW --no-compress --mkpath \ /var/lib/docker/volumes/sentry-postgres \ /var/lib/docker/volumes/sentry-clickhouse \ diff --git a/install/upgrade-clickhouse.sh b/install/upgrade-clickhouse.sh index 05e74bb00b9..bd69d7bf746 100644 --- a/install/upgrade-clickhouse.sh +++ b/install/upgrade-clickhouse.sh @@ -1,7 +1,7 @@ echo "${_group}Upgrading Clickhouse ..." # First check to see if user is upgrading by checking for existing clickhouse volume -if [[ -n "$(docker volume ls -q --filter name=sentry-clickhouse)" ]]; then +if docker compose ps -a | grep -q clickhouse; then # Start clickhouse if it is not already running $dc up --wait clickhouse From 11faae66acdc6a1dcbc72a09d8ee316f52daeadb Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 15 Jan 2025 18:05:59 +0000 Subject: [PATCH 112/305] release: 25.1.0 --- .env | 10 +++++----- CHANGELOG.md | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 5688114306b..289ea70edcf 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.1.0 +SNUBA_IMAGE=getsentry/snuba:25.1.0 +RELAY_IMAGE=getsentry/relay:25.1.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.1.0 +VROOM_IMAGE=getsentry/vroom:25.1.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d9cfebee2..6da8315bbf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 25.1.0 + +### Various fixes & improvements + +- ci: Use generic Docker volume cache action (#3524) by @BYK +- ci: Less volatile cache keys (#3522) by @BYK +- docs: include regular env file on wrap-up (#3523) by @aldy505 +- ci: Faster and smarter backup/restore tests (#3516) by @BYK +- fix: Fix the new e2e action to be portable (#3520) by @BYK +- ci: Move e2e test action into the repo (#3519) by @BYK +- ci: Only test on compose 2.26 w/ customizations (#3506) by @BYK +- ci: Skip DB ops during install completely on cache hit (#3496) by @BYK +- chore: Remove everything zookeeper (#3499) by @hubertdeng123 +- ci: Cache postgres volume after first migration (#3488) by @BYK +- fix: Remove the extra space in the log file names (#3212) by @melnele +- ref(snuba): Combine bootstrap & migrate for faster bootstrap (#3491) by @BYK +- ref(geoip): Remove geoipupdate from compose (#3490) by @BYK +- build(deps): bump actions/create-github-app-token from 1.11.0 to 1.11.1 (#3492) by @dependabot + ## 24.12.1 ### Various fixes & improvements From c075cf570a2b41a489220dd2df68b74116dc3dfa Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 15 Jan 2025 18:25:34 +0000 Subject: [PATCH 113/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 289ea70edcf..5688114306b 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.1.0 -SNUBA_IMAGE=getsentry/snuba:25.1.0 -RELAY_IMAGE=getsentry/relay:25.1.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.1.0 -VROOM_IMAGE=getsentry/vroom:25.1.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 63b6c0afa7798e18c33203fa3290ae0254c77ddf Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 16 Jan 2025 17:59:38 +0000 Subject: [PATCH 114/305] test: Reorganize backup/restore tests for speed and reliability (#3537) We should do the backup/restore tests _after_ we do the basic tests. This is both more efficient as we avoid an extra up/down cycle and more meaningful as we will back up and restore an actually used system. A bit hard to measure directly as this also moves the initial `docker compose up -w` into the test suite but a random run without this patch took about 10m 49s to finish for the testing part whereas with the patch it came down to 9m 10s so **almost 2 minutes faster**! --- _integration-test/conftest.py | 5 ++++ .../{test_run.py => test_01_basics.py} | 0 .../{test_backup.py => test_02_backup.py} | 30 +++++-------------- action.yaml | 3 +- sentry-admin.sh | 3 +- 5 files changed, 16 insertions(+), 25 deletions(-) rename _integration-test/{test_run.py => test_01_basics.py} (100%) rename _integration-test/{test_backup.py => test_02_backup.py} (84%) diff --git a/_integration-test/conftest.py b/_integration-test/conftest.py index e80cef95e6a..e73a7f286c5 100644 --- a/_integration-test/conftest.py +++ b/_integration-test/conftest.py @@ -12,6 +12,11 @@ @pytest.fixture(scope="session", autouse=True) def configure_self_hosted_environment(request): + subprocess.run( + ["docker", "compose", "--ansi", "never", "up", "--wait"], + check=True, + capture_output=True, + ) # Create test user subprocess.run( [ diff --git a/_integration-test/test_run.py b/_integration-test/test_01_basics.py similarity index 100% rename from _integration-test/test_run.py rename to _integration-test/test_01_basics.py diff --git a/_integration-test/test_backup.py b/_integration-test/test_02_backup.py similarity index 84% rename from _integration-test/test_backup.py rename to _integration-test/test_02_backup.py index b73e0cfb163..0898f9a951c 100644 --- a/_integration-test/test_backup.py +++ b/_integration-test/test_02_backup.py @@ -20,7 +20,7 @@ def test_sentry_admin(setup_backup_restore_env_variables): assert "Usage: ./sentry-admin.sh permissions" in output -def test_backup(setup_backup_restore_env_variables): +def test_01_backup(setup_backup_restore_env_variables): # Docker was giving me permission issues when trying to create this file and write to it even after giving read + write access # to group and owner. Instead, try creating the empty file and then give everyone write access to the backup file file_path = os.path.join(os.getcwd(), "sentry", "backup.json") @@ -41,19 +41,22 @@ def test_backup(setup_backup_restore_env_variables): assert os.path.getsize(file_path) > 0 -def test_import(setup_backup_restore_env_variables): +def test_02_import(setup_backup_restore_env_variables): # Bring postgres down and recreate the docker volume subprocess.run(["docker", "compose", "--ansi", "never", "down"], check=True) # We reset all DB-related volumes here and not just Postgres although the backups # are only for Postgres. The reason is to get a "clean slate" as we need the Kafka - # and Clickhouse volumes to be back to their initial state as well ( without any events) - # We cannot just rm and create them as they still need migrations. + # and Clickhouse volumes to be back to their initial state as well (without any events) + # We cannot just rm and create them as they still need the migrations. for name in ("postgres", "clickhouse", "kafka"): subprocess.run(["docker", "volume", "rm", f"sentry-{name}"], check=True) + subprocess.run(["docker", "volume", "create", f"sentry-{name}"], check=True) subprocess.run( [ "rsync", "-aW", + "--super", + "--numeric-ids", "--no-compress", "--mkpath", join(os.environ["RUNNER_TEMP"], "volumes", f"sentry-{name}", ""), @@ -62,24 +65,6 @@ def test_import(setup_backup_restore_env_variables): check=True, capture_output=True, ) - subprocess.run(["docker", "volume", "create", f"sentry-{name}"], check=True) - - subprocess.run( - [ - "docker", - "run", - "--rm", - "-v", - "sentry-kafka:/data", - "busybox", - "chown", - "-R", - "1000:1000", - "/data", - ], - check=True, - capture_output=True, - ) subprocess.run( ["docker", "compose", "--ansi", "never", "up", "--wait"], @@ -97,3 +82,4 @@ def test_import(setup_backup_restore_env_variables): ], check=True, ) + # TODO: Check something actually restored here like the test user we have from earlier diff --git a/action.yaml b/action.yaml index ec5897f0a27..9f87b93d4f1 100644 --- a/action.yaml +++ b/action.yaml @@ -111,13 +111,12 @@ runs: shell: bash run: | sudo chown root /usr/bin/rsync && sudo chmod u+s /usr/bin/rsync - rsync -aW --no-compress --mkpath \ + rsync -aW --super --numeric-ids --no-compress --mkpath \ /var/lib/docker/volumes/sentry-postgres \ /var/lib/docker/volumes/sentry-clickhouse \ /var/lib/docker/volumes/sentry-kafka \ "$RUNNER_TEMP/volumes/" cd ${{ github.action_path }} - docker compose up --wait pytest -x --cov --junitxml=junit.xml _integration-test/ - name: Upload coverage to Codecov diff --git a/sentry-admin.sh b/sentry-admin.sh index 3db5f2ed044..ef0e75e98a5 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -22,7 +22,8 @@ on the host filesystem. Commands that write files should write them to the '/sen # Actual invocation that runs the command in the container. invocation() { - $dcr --quiet-pull -v "$VOLUME_MAPPING" -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 + $dc up postgres --wait + $dcr --no-deps --quiet-pull -v "$VOLUME_MAPPING" -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 } # Function to modify lines starting with `Usage: sentry` to say `Usage: ./sentry-admin.sh` instead. From 3913a9f0c7cfcaf5396d257ba097b0688468a036 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 16 Jan 2025 18:10:14 +0000 Subject: [PATCH 115/305] ci: Even better cache keys and granular caching (#3534) Just starting up services for Snuba or Sentry migrations takes up to a minute sometimes and we do this even when there are no migrations, just because one of the Sentry or Snuba migrations change. This patch splits the caches up so only the necessary one runs, saving further time. It also uses the `LATEST_TAG` as the cache key for upgrade tests as the image versions or data will never change for a certain tag once it is release. --- .github/workflows/test.yml | 16 +++---- action.yaml | 62 +++++++++++++++++++++----- install/bootstrap-snuba.sh | 4 +- install/set-up-and-migrate-database.sh | 4 +- 4 files changed, 59 insertions(+), 27 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3e471c84baa..5c01abc6c4a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,22 +56,13 @@ jobs: sudo curl -L https://github.com/docker/compose/releases/download/v2.26.0/docker-compose-`uname -s`-`uname -m` -o "/usr/local/lib/docker/cli-plugins/docker-compose" sudo chmod +x "/usr/local/lib/docker/cli-plugins/docker-compose" - - name: Compute Docker Volume Cache Key - id: cache_key - run: | - source .env - SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c 'ls -Rv1rpq src/sentry/migrations/' | md5sum | cut -d ' ' -f 1) - echo "SENTRY_MIGRATIONS_MD5=$SENTRY_MIGRATIONS_MD5" >> $GITHUB_OUTPUT - SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c 'ls -Rv1rpq snuba/snuba_migrations/**/*.py' | md5sum | cut -d ' ' -f 1) - echo "SNUBA_MIGRATIONS_MD5=$SNUBA_MIGRATIONS_MD5" >> $GITHUB_OUTPUT - - name: Restore DB Volumes Cache id: restore_cache uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-v6-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} + key: db-volumes-v6-${{ env.LATEST_TAG }} restore-keys: | - db-volumes-v6-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + db-volumes-v6-${{ env.LATEST_TAG }} db-volumes-v6- volumes: | sentry-postgres @@ -80,7 +71,10 @@ jobs: - name: Install ${{ env.LATEST_TAG }} env: + # Remove SKIP_DB_MIGRATIONS after releasing 25.1.1 or 25.2.0 SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} + SKIP_SENTRY_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} + SKIP_SNUBA_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} run: | # This is to compensate for a bug in upgrade-clickhouse where # if we have sentry-clickhouse volume without the rest, it fails diff --git a/action.yaml b/action.yaml index 9f87b93d4f1..924e4c856d3 100644 --- a/action.yaml +++ b/action.yaml @@ -54,34 +54,58 @@ runs: sudo curl -L https://github.com/docker/compose/releases/download/${{ env.COMPOSE_VERSION }}/docker-compose-`uname -s`-`uname -m` -o "${{ env.COMPOSE_PATH }}/docker-compose" sudo chmod +x "${{ env.COMPOSE_PATH }}/docker-compose" - - name: Compute Docker Volume Cache Key + - name: Compute Docker Volume Cache Keys id: cache_key shell: bash run: | source ${{ github.action_path }}/.env # See https://explainshell.com/explain?cmd=ls%20-Rv1rpq # for that long `ls` command - SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c 'ls -Rv1rpq src/sentry/migrations/' | md5sum | cut -d ' ' -f 1) + SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c '{ ls -Rv1rpq src/sentry/migrations/; sed -n "/KAFKA_TOPIC_TO_CLUSTER/,/}/p" src/sentry/conf/server.py; }' | md5sum | cut -d ' ' -f 1) echo "SENTRY_MIGRATIONS_MD5=$SENTRY_MIGRATIONS_MD5" >> $GITHUB_OUTPUT - SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c 'ls -Rv1rpq snuba/snuba_migrations/**/*.py' | md5sum | cut -d ' ' -f 1) + SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c '{ ls -Rv1rpq snuba/snuba_migrations/**/*.py; sed -n "/^class Topic(Enum):/,/\\n\\n/p" snuba/utils/streams/topics.py; }' | md5sum | cut -d ' ' -f 1) echo "SNUBA_MIGRATIONS_MD5=$SNUBA_MIGRATIONS_MD5" >> $GITHUB_OUTPUT - - name: Restore DB Volumes Cache - id: restore_cache + - name: Restore Sentry Volume Cache + id: restore_cache_sentry uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-v6-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} + key: db-volumes-sentry-v1-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} restore-keys: | - db-volumes-v6-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} - db-volumes-v6- + db-volumes-sentry-v1- volumes: | sentry-postgres + + - name: Restore Snuba Volume Cache + id: restore_cache_snuba + uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd + with: + key: db-volumes-snuba-v1-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + restore-keys: | + db-volumes-snuba-v1- + volumes: | sentry-clickhouse + + - name: Restore Kafka Volume Cache + id: restore_cache_kafka + uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd + with: + key: db-volumes-kafka-v1-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + restore-keys: | + db-volumes-kafka-v1-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + db-volumes-kafka-v1-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }}- + db-volumes-kafka-v1- + volumes: | sentry-kafka - name: Install self-hosted env: - SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} + # Note that cache keys for Sentry and Snuba have their respective Kafka configs built into them + # and the Kafka volume cache is comprises both keys. This way we can omit the Kafka cache hit + # in here to still avoid running Sentry or Snuba migrations if only one of their Kafka config has + # changed. Heats up your head a bit but if you think about it, it makes sense. + SKIP_SENTRY_MIGRATIONS: ${{ steps.restore_cache_sentry.outputs.cache-hit == 'true' && '1' || '' }} + SKIP_SNUBA_MIGRATIONS: ${{ steps.restore_cache_snuba.outputs.cache-hit == 'true' && '1' || '' }} shell: bash run: | cd ${{ github.action_path }} @@ -97,14 +121,28 @@ runs: ./install.sh --no-report-self-hosted-issues --skip-commit-check - - name: Save DB Volumes Cache - if: steps.restore_cache.outputs.cache-hit != 'true' + - name: Save Sentry Volume Cache + if: steps.restore_cache_sentry.outputs.cache-hit != 'true' uses: BYK/docker-volume-cache-action/save@be89365902126f508dcae387a32ec3712df6b1cd with: - key: ${{ steps.restore_cache.outputs.cache-primary-key }} + key: ${{ steps.restore_cache_sentry.outputs.cache-primary-key }} volumes: | sentry-postgres + + - name: Save Snuba Volume Cache + if: steps.restore_cache_snuba.outputs.cache-hit != 'true' + uses: BYK/docker-volume-cache-action/save@be89365902126f508dcae387a32ec3712df6b1cd + with: + key: ${{ steps.restore_cache_snuba.outputs.cache-primary-key }} + volumes: | sentry-clickhouse + + - name: Save Kafka Volume Cache + if: steps.restore_cache_kafka.outputs.cache-hit != 'true' + uses: BYK/docker-volume-cache-action/save@be89365902126f508dcae387a32ec3712df6b1cd + with: + key: ${{ steps.restore_cache_kafka.outputs.cache-primary-key }} + volumes: | sentry-kafka - name: Integration Test diff --git a/install/bootstrap-snuba.sh b/install/bootstrap-snuba.sh index 20666302ade..496becd6c57 100644 --- a/install/bootstrap-snuba.sh +++ b/install/bootstrap-snuba.sh @@ -1,9 +1,9 @@ echo "${_group}Bootstrapping and migrating Snuba ..." -if [[ -z "${SKIP_DB_MIGRATIONS:-}" ]]; then +if [[ -z "${SKIP_SNUBA_MIGRATIONS:-}" ]]; then $dcr snuba-api bootstrap --force else - echo "Skipped DB migrations due to SKIP_DB_MIGRATIONS=$SKIP_DB_MIGRATIONS" + echo "Skipped DB migrations due to SKIP_SNUBA_MIGRATIONS=$SKIP_SNUBA_MIGRATIONS" fi echo "${_endgroup}" diff --git a/install/set-up-and-migrate-database.sh b/install/set-up-and-migrate-database.sh index a1cc8323e89..2d4e13208e3 100644 --- a/install/set-up-and-migrate-database.sh +++ b/install/set-up-and-migrate-database.sh @@ -1,6 +1,6 @@ echo "${_group}Setting up / migrating database ..." -if [[ -z "${SKIP_DB_MIGRATIONS:-}" ]]; then +if [[ -z "${SKIP_SENTRY_MIGRATIONS:-}" ]]; then # Fixes https://github.com/getsentry/self-hosted/issues/2758, where a migration fails due to indexing issue $dc up --wait postgres @@ -31,6 +31,6 @@ with connection.cursor() as cursor: $dcr web upgrade --create-kafka-topics fi else - echo "Skipped DB migrations due to SKIP_DB_MIGRATIONS=$SKIP_DB_MIGRATIONS" + echo "Skipped DB migrations due to SKIP_SENTRY_MIGRATIONS=$SKIP_SENTRY_MIGRATIONS" fi echo "${_endgroup}" From 559e7324686b8b0a7fa6f4783013cbb7a81d7080 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 16 Jan 2025 21:45:07 +0000 Subject: [PATCH 116/305] breaking: Upgrade min Compose version to 2.23.2 (#3535) In this version, there's a new `--pull` argument for `docker compose run` which we will start leveraging, especially with `sentry-admin` command. Should come with a slight speed boost. --- .github/workflows/test.yml | 16 +++++++--------- _unit-test/js-sdk-assets-test.sh | 7 ++++--- action.yaml | 17 ++--------------- get-compose-action/action.yaml | 19 +++++++++++++++++++ install/_min-requirements.sh | 2 +- install/dc-detect-version.sh | 2 +- sentry-admin.sh | 2 +- 7 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 get-compose-action/action.yaml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5c01abc6c4a..af1e624dc2f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,6 +27,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Get Compose + uses: ./get-compose-action + - name: Unit Tests run: ./unit-test.sh @@ -42,20 +45,15 @@ jobs: LATEST_TAG=$(curl -s https://api.github.com/repos/getsentry/self-hosted/releases/latest | jq -r '.tag_name') echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV + - name: Get Compose + # TODO: Replace this with `@master` after landing + uses: getsentry/self-hosted/get-compose-action@byk/ref/upgrade-compose + - name: Checkout latest release uses: actions/checkout@v4 with: ref: ${{ env.LATEST_TAG }} - - name: Get Compose - run: | - # Docker Compose v1 is installed here, remove it - sudo rm -f "/usr/local/bin/docker-compose" - sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" - sudo mkdir -p "/usr/local/lib/docker/cli-plugins" - sudo curl -L https://github.com/docker/compose/releases/download/v2.26.0/docker-compose-`uname -s`-`uname -m` -o "/usr/local/lib/docker/cli-plugins/docker-compose" - sudo chmod +x "/usr/local/lib/docker/cli-plugins/docker-compose" - - name: Restore DB Volumes Cache id: restore_cache uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd diff --git a/_unit-test/js-sdk-assets-test.sh b/_unit-test/js-sdk-assets-test.sh index 7177f559ba9..bd898acf6a7 100755 --- a/_unit-test/js-sdk-assets-test.sh +++ b/_unit-test/js-sdk-assets-test.sh @@ -3,14 +3,15 @@ source _unit-test/_test_setup.sh source install/dc-detect-version.sh $dcb --force-rm web +$dc pull nginx export SETUP_JS_SDK_ASSETS=1 source install/setup-js-sdk-assets.sh -sdk_files=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx ls -lah /var/www/js-sdk/) -sdk_tree=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx tree /var/www/js-sdk/ | tail -n 1) -non_empty_file_count=$(docker compose run --no-deps --rm -v "sentry-nginx-www:/var/www" nginx find /var/www/js-sdk/ -type f -size +1k | wc -l) +sdk_files=$($dcr --no-deps -v "sentry-nginx-www:/var/www" nginx ls -lah /var/www/js-sdk/) +sdk_tree=$($dcr --no-deps -v "sentry-nginx-www:/var/www" nginx tree /var/www/js-sdk/ | tail -n 1) +non_empty_file_count=$($dcr --no-deps -v "sentry-nginx-www:/var/www" nginx find /var/www/js-sdk/ -type f -size +1k | wc -l) # `sdk_files` should contains 5 lines, '4.*', '5.*', '6.*', `7.*` and `8.*` echo $sdk_files diff --git a/action.yaml b/action.yaml index 924e4c856d3..846bca0a875 100644 --- a/action.yaml +++ b/action.yaml @@ -39,26 +39,13 @@ runs: fi - name: Get Compose - env: - COMPOSE_PATH: /usr/local/lib/docker/cli-plugins - COMPOSE_VERSION: "v2.26.0" - shell: bash - run: | - # Always remove `docker compose` support as that's the newer version - # and comes installed by default nowadays. - sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" - # Docker Compose v1 is installed here, remove it - sudo rm -f "/usr/local/bin/docker-compose" - sudo rm -f "${{ env.COMPOSE_PATH }}/docker-compose" - sudo mkdir -p "${{ env.COMPOSE_PATH }}" - sudo curl -L https://github.com/docker/compose/releases/download/${{ env.COMPOSE_VERSION }}/docker-compose-`uname -s`-`uname -m` -o "${{ env.COMPOSE_PATH }}/docker-compose" - sudo chmod +x "${{ env.COMPOSE_PATH }}/docker-compose" + uses: ./get-compose-action - name: Compute Docker Volume Cache Keys id: cache_key shell: bash run: | - source ${{ github.action_path }}/.env + source ${{ github.action_path }}.env # See https://explainshell.com/explain?cmd=ls%20-Rv1rpq # for that long `ls` command SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c '{ ls -Rv1rpq src/sentry/migrations/; sed -n "/KAFKA_TOPIC_TO_CLUSTER/,/}/p" src/sentry/conf/server.py; }' | md5sum | cut -d ' ' -f 1) diff --git a/get-compose-action/action.yaml b/get-compose-action/action.yaml new file mode 100644 index 00000000000..17d5993e70d --- /dev/null +++ b/get-compose-action/action.yaml @@ -0,0 +1,19 @@ +name: "Get Docker Compose" +inputs: + version: + required: false + default: 2.32.3 + description: "Docker Compose version" + +runs: + using: "composite" + steps: + - name: Get Compose + shell: bash + run: | + # Docker Compose v1 is installed here, remove it + sudo rm -f "/usr/local/bin/docker-compose" + sudo rm -f "/usr/local/lib/docker/cli-plugins/docker-compose" + sudo mkdir -p "/usr/local/lib/docker/cli-plugins" + sudo curl -L https://github.com/docker/compose/releases/download/v${{ inputs.version }}/docker-compose-`uname -s`-`uname -m` -o "/usr/local/lib/docker/cli-plugins/docker-compose" + sudo chmod +x "/usr/local/lib/docker/cli-plugins/docker-compose" diff --git a/install/_min-requirements.sh b/install/_min-requirements.sh index 2180c6a9a97..c518508e2f3 100644 --- a/install/_min-requirements.sh +++ b/install/_min-requirements.sh @@ -1,6 +1,6 @@ # Don't forget to update the README and other docs when you change these! MIN_DOCKER_VERSION='19.03.6' -MIN_COMPOSE_VERSION='2.19.0' +MIN_COMPOSE_VERSION='2.32.2' # 16 GB minimum host RAM, but there'll be some overhead outside of what # can be allotted to docker diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index 64e814e1ecd..ccee1b5eebe 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -16,7 +16,7 @@ else dc="$dc_base --ansi never" fi proxy_args="--build-arg http_proxy=${http_proxy:-} --build-arg https_proxy=${https_proxy:-} --build-arg no_proxy=${no_proxy:-}" -dcr="$dc run --rm" +dcr="$dc run --pull=never --rm" dcb="$dc build $proxy_args" dbuild="docker build $proxy_args" diff --git a/sentry-admin.sh b/sentry-admin.sh index ef0e75e98a5..e910cb1dc95 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -23,7 +23,7 @@ on the host filesystem. Commands that write files should write them to the '/sen # Actual invocation that runs the command in the container. invocation() { $dc up postgres --wait - $dcr --no-deps --quiet-pull -v "$VOLUME_MAPPING" -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 + $dcr --no-deps -v "$VOLUME_MAPPING" -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 } # Function to modify lines starting with `Usage: sentry` to say `Usage: ./sentry-admin.sh` instead. From 52a1901f75409436ef14d48885d3499b3c3ebec2 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Thu, 16 Jan 2025 21:58:18 +0000 Subject: [PATCH 117/305] ci: Move self-contained action reference to master branch (#3538) Required follow up to #3535 --- .github/workflows/test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index af1e624dc2f..8dba1227a40 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,8 +46,7 @@ jobs: echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV - name: Get Compose - # TODO: Replace this with `@master` after landing - uses: getsentry/self-hosted/get-compose-action@byk/ref/upgrade-compose + uses: getsentry/self-hosted/get-compose-action@master - name: Checkout latest release uses: actions/checkout@v4 From 7a897618df0f4c3b4d113684c40b74cb762a5a42 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Thu, 16 Jan 2025 23:16:18 -0800 Subject: [PATCH 118/305] fix: Caching of sentry migrations should cover additional folders (#3542) We need to care about more than just src/sentry/migrations. We will need to account for files in src/sentry/**/migrations/* Taken from https://github.com/getsentry/sentry/blob/afd74698180066223dee53991b7db26ca80ea3e5/.github/file-filters.yml#L90 --- action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 846bca0a875..7601c9057db 100644 --- a/action.yaml +++ b/action.yaml @@ -48,7 +48,7 @@ runs: source ${{ github.action_path }}.env # See https://explainshell.com/explain?cmd=ls%20-Rv1rpq # for that long `ls` command - SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c '{ ls -Rv1rpq src/sentry/migrations/; sed -n "/KAFKA_TOPIC_TO_CLUSTER/,/}/p" src/sentry/conf/server.py; }' | md5sum | cut -d ' ' -f 1) + SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c '{ ls -Rv1rpq src/sentry/**/migrations/*; sed -n "/KAFKA_TOPIC_TO_CLUSTER/,/}/p" src/sentry/conf/server.py; }' | md5sum | cut -d ' ' -f 1) echo "SENTRY_MIGRATIONS_MD5=$SENTRY_MIGRATIONS_MD5" >> $GITHUB_OUTPUT SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c '{ ls -Rv1rpq snuba/snuba_migrations/**/*.py; sed -n "/^class Topic(Enum):/,/\\n\\n/p" snuba/utils/streams/topics.py; }' | md5sum | cut -d ' ' -f 1) echo "SNUBA_MIGRATIONS_MD5=$SNUBA_MIGRATIONS_MD5" >> $GITHUB_OUTPUT From 0ce2cd7e326e1e31df90469dbef734cdf5b4aacc Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Thu, 16 Jan 2025 23:31:22 -0800 Subject: [PATCH 119/305] fix: Use correct path for get compose action (#3539) --- action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 7601c9057db..c177615c725 100644 --- a/action.yaml +++ b/action.yaml @@ -39,7 +39,7 @@ runs: fi - name: Get Compose - uses: ./get-compose-action + uses: getsentry/self-hosted/get-compose-action@master - name: Compute Docker Volume Cache Keys id: cache_key From 9ceb00f739d478c83f19059dee7cc0b7121b11b8 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Fri, 17 Jan 2025 03:51:31 -0800 Subject: [PATCH 120/305] chore: Remove upgrade test (#3541) As discussed, removing the upgrade test since it doesn't provide that much utility as we are already testing upgrades from restoring docker volumes from cache --- .github/workflows/test.yml | 71 -------------------------------------- 1 file changed, 71 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8dba1227a40..672a2802e78 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,77 +33,6 @@ jobs: - name: Unit Tests run: ./unit-test.sh - upgrade-test: - if: github.repository_owner == 'getsentry' - runs-on: ubuntu-22.04 - name: "Sentry upgrade test" - env: - REPORT_SELF_HOSTED_ISSUES: 0 - steps: - - name: Get latest self-hosted release version - run: | - LATEST_TAG=$(curl -s https://api.github.com/repos/getsentry/self-hosted/releases/latest | jq -r '.tag_name') - echo "LATEST_TAG=$LATEST_TAG" >> $GITHUB_ENV - - - name: Get Compose - uses: getsentry/self-hosted/get-compose-action@master - - - name: Checkout latest release - uses: actions/checkout@v4 - with: - ref: ${{ env.LATEST_TAG }} - - - name: Restore DB Volumes Cache - id: restore_cache - uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd - with: - key: db-volumes-v6-${{ env.LATEST_TAG }} - restore-keys: | - db-volumes-v6-${{ env.LATEST_TAG }} - db-volumes-v6- - volumes: | - sentry-postgres - sentry-clickhouse - sentry-kafka - - - name: Install ${{ env.LATEST_TAG }} - env: - # Remove SKIP_DB_MIGRATIONS after releasing 25.1.1 or 25.2.0 - SKIP_DB_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} - SKIP_SENTRY_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} - SKIP_SNUBA_MIGRATIONS: ${{ steps.restore_cache.outputs.cache-hit == 'true' && '1' || '' }} - run: | - # This is to compensate for a bug in upgrade-clickhouse where - # if we have sentry-clickhouse volume without the rest, it fails - # We may get sentry-clickhouse from the cache step above - source install/create-docker-volumes.sh - ./install.sh - - - name: Save DB Volumes Cache - if: steps.restore_cache.outputs.cache-hit != 'true' - uses: BYK/docker-volume-cache-action/save@be89365902126f508dcae387a32ec3712df6b1cd - with: - key: ${{ steps.restore_cache.outputs.cache-primary-key }} - volumes: | - sentry-postgres - sentry-clickhouse - sentry-kafka - - - name: Checkout current ref - uses: actions/checkout@v4 - - - name: Install current ref - run: | - # This is for the cache restore on Kafka to work in older releases - docker run --rm -v "sentry-kafka:/data" busybox chown -R 1000:1000 /data - ./install.sh - - - name: Inspect failure - if: failure() - run: | - docker compose ps - docker compose logs - integration-test: if: github.repository_owner == 'getsentry' runs-on: ubuntu-22.04 From 3984a876112f9c1c10a94479796fb979741b8310 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 17 Jan 2025 17:40:40 +0000 Subject: [PATCH 121/305] fix: github.action_path may not have trailing slash (#3547) --- action.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/action.yaml b/action.yaml index c177615c725..5370eda824f 100644 --- a/action.yaml +++ b/action.yaml @@ -18,7 +18,7 @@ runs: shell: bash run: | image_var=$(echo ${{ inputs.project_name }}_IMAGE | tr '[:lower:]' '[:upper:]') - echo "${image_var}=${{ inputs.image_url }}" >> ${{ github.action_path }}.env + echo "${image_var}=${{ inputs.image_url }}" >> ${{ github.action_path }}/.env - name: Setup dev environment shell: bash @@ -45,7 +45,7 @@ runs: id: cache_key shell: bash run: | - source ${{ github.action_path }}.env + source ${{ github.action_path }}/.env # See https://explainshell.com/explain?cmd=ls%20-Rv1rpq # for that long `ls` command SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c '{ ls -Rv1rpq src/sentry/**/migrations/*; sed -n "/KAFKA_TOPIC_TO_CLUSTER/,/}/p" src/sentry/conf/server.py; }' | md5sum | cut -d ' ' -f 1) From e1870f8ecbd9f2f2d707f45a702867148b7fd819 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 17 Jan 2025 20:29:23 +0000 Subject: [PATCH 122/305] ci: Remove obsolete `dcr up -w` from import test (#3544) I _think_ we can get away with this but let's see what the CI thinks. If it passes, it should save us another minuter or two. --- _integration-test/test_02_backup.py | 5 ----- sentry-admin.sh | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/_integration-test/test_02_backup.py b/_integration-test/test_02_backup.py index 0898f9a951c..ad42824524e 100644 --- a/_integration-test/test_02_backup.py +++ b/_integration-test/test_02_backup.py @@ -66,11 +66,6 @@ def test_02_import(setup_backup_restore_env_variables): capture_output=True, ) - subprocess.run( - ["docker", "compose", "--ansi", "never", "up", "--wait"], - check=True, - capture_output=True, - ) sentry_admin_sh = os.path.join(os.getcwd(), "sentry-admin.sh") subprocess.run( [ diff --git a/sentry-admin.sh b/sentry-admin.sh index e910cb1dc95..386b3d57011 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -23,6 +23,7 @@ on the host filesystem. Commands that write files should write them to the '/sen # Actual invocation that runs the command in the container. invocation() { $dc up postgres --wait + $dc up redis --wait $dcr --no-deps -v "$VOLUME_MAPPING" -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 } From d637ed19fefb77cc7d6dab017b9da3ccceb257ca Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Wed, 22 Jan 2025 15:15:53 -0500 Subject: [PATCH 123/305] Hand off open-source to dev-infra (#3549) --- .github/dependabot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f83c1c8e04b..31589ecff7a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,7 +6,7 @@ updates: interval: daily open-pull-requests-limit: 0 # only security updates reviewers: - - "@getsentry/open-source" + - "@getsentry/dev-infra" - "@getsentry/security" - package-ecosystem: "github-actions" @@ -15,5 +15,5 @@ updates: # Check for updates to GitHub Actions every week interval: "weekly" reviewers: - - "@getsentry/open-source" + - "@getsentry/dev-infra" - "@getsentry/security" From 95761f7d6259171b8d1b1bbbb4b595c3098159b3 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Fri, 24 Jan 2025 22:14:51 +0000 Subject: [PATCH 124/305] ref: Simpler and more accurate cache keys (#3553) --- action.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/action.yaml b/action.yaml index 5370eda824f..3bdf597bf3e 100644 --- a/action.yaml +++ b/action.yaml @@ -48,16 +48,16 @@ runs: source ${{ github.action_path }}/.env # See https://explainshell.com/explain?cmd=ls%20-Rv1rpq # for that long `ls` command - SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c '{ ls -Rv1rpq src/sentry/**/migrations/*; sed -n "/KAFKA_TOPIC_TO_CLUSTER/,/}/p" src/sentry/conf/server.py; }' | md5sum | cut -d ' ' -f 1) + SENTRY_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SENTRY_IMAGE -c '{ cat migrations_lockfile.txt; grep -Poz "(?s)(?<=class Topic\\(Enum\\):\\n).+?(?=\\n\\n\\n)" src/sentry/conf/types/kafka_definition.py; }' | md5sum | cut -d ' ' -f 1) echo "SENTRY_MIGRATIONS_MD5=$SENTRY_MIGRATIONS_MD5" >> $GITHUB_OUTPUT - SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c '{ ls -Rv1rpq snuba/snuba_migrations/**/*.py; sed -n "/^class Topic(Enum):/,/\\n\\n/p" snuba/utils/streams/topics.py; }' | md5sum | cut -d ' ' -f 1) + SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c '{ ls -Rv1rpq snuba/snuba_migrations/**/*.py; grep -Poz "(?s)(?<=class Topic\\(Enum\\):\\n).+?(?=\\n\\n\\n)" snuba/utils/streams/topics.py; }' | md5sum | cut -d ' ' -f 1) echo "SNUBA_MIGRATIONS_MD5=$SNUBA_MIGRATIONS_MD5" >> $GITHUB_OUTPUT - name: Restore Sentry Volume Cache id: restore_cache_sentry uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-sentry-v1-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} + key: db-volumes-sentry-v2-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} restore-keys: | db-volumes-sentry-v1- volumes: | @@ -67,7 +67,7 @@ runs: id: restore_cache_snuba uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-snuba-v1-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + key: db-volumes-snuba-v2-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} restore-keys: | db-volumes-snuba-v1- volumes: | From 9eea781e1c189ebc2f2f757efa98b82f80fb7496 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 25 Jan 2025 16:53:50 +0000 Subject: [PATCH 125/305] feat: Require both inputs to be set on action (#3554) Came as a feature request from @untitaker and I think it makes a lot of sense --------- Co-authored-by: Hubert Deng --- action.yaml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/action.yaml b/action.yaml index 3bdf597bf3e..ebc22f4831c 100644 --- a/action.yaml +++ b/action.yaml @@ -13,12 +13,22 @@ inputs: runs: using: "composite" steps: - - name: Configure to use the test image - if: inputs.project_name && inputs.image_url + - name: Validate inputs and configure test image shell: bash + env: + PROJECT_NAME: ${{ inputs.project_name }} + IMAGE_URL: ${{ inputs.image_url }} run: | - image_var=$(echo ${{ inputs.project_name }}_IMAGE | tr '[:lower:]' '[:upper:]') - echo "${image_var}=${{ inputs.image_url }}" >> ${{ github.action_path }}/.env + if [[ -n "$PROJECT_NAME" && -n "$IMAGE_URL" ]]; then + image_var=$(echo "${PROJECT_NAME}_IMAGE" | tr '[:lower:]' '[:upper:]') + echo "${image_var}=$IMAGE_URL" >> ${{ github.action_path }}/.env + elif [[ -z "$PROJECT_NAME" && -z "$IMAGE_URL" ]]; then + echo "No project name and image URL set. Skipping image configuration." + else + echo "You must set both project_name and image_url or unset both." + echo "project_name: $PROJECT_NAME, image_url: $IMAGE_URL" + exit 1 + fi - name: Setup dev environment shell: bash From cfb0491f6341c8c8b66ac9b14056ae481f4e253c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 22:11:27 +0000 Subject: [PATCH 126/305] build(deps): bump actions/create-github-app-token from 1.11.1 to 1.11.2 (#3561) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1.11.1 to 1.11.2. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/c1a285145b9d317df6ced56c09f525b5c2b6f755...136412a57a7081aa63c935a2cc2918f76c34f514) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 38e929334f6..1b3f442263f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1 + uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From ee3cbf0f9101cca61033916d691f18d7a9ebb94e Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 4 Feb 2025 19:41:12 +0700 Subject: [PATCH 127/305] feat: merge `.env` and `.env.custom` file during installation (#3564) Closes https://github.com/getsentry/self-hosted/issues/3558 --- _unit-test/merge-env-file-test.sh | 25 +++++++++++++++++++++++++ install/_lib.sh | 10 +++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100755 _unit-test/merge-env-file-test.sh diff --git a/_unit-test/merge-env-file-test.sh b/_unit-test/merge-env-file-test.sh new file mode 100755 index 00000000000..156110d0060 --- /dev/null +++ b/_unit-test/merge-env-file-test.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# This is a test file for a part of `_lib.sh`, where we read `.env.custom` file if there is one. +# We only want to give very minimal value to the `.env.custom` file, and expect that it would +# be merged with the original `.env` file, with the `.env.custom` file taking precedence. +cat <".env.custom" +SENTRY_EVENT_RETENTION_DAYS=10 +EOF + +# The `_test_setup.sh` script sources `install/_lib.sh`, so.. finger crossed this should works. +source _unit-test/_test_setup.sh + +rm -f .env.custom + +echo "Expecting SENTRY_EVENT_RETENTION_DAYS to be 10, got ${SENTRY_EVENT_RETENTION_DAYS}" +test "$SENTRY_EVENT_RETENTION_DAYS" == "10" +echo "Pass" +echo "Expecting SENTRY_BIND to be 9000, got ${SENTRY_BIND}" +test "$SENTRY_BIND" == "9000" +echo "Pass" +echo "Expecting COMPOSE_PROJECT_NAME to be sentry-self-hosted, got ${COMPOSE_PROJECT_NAME}" +test "$COMPOSE_PROJECT_NAME" == "sentry-self-hosted" +echo "Pass" + +report_success diff --git a/install/_lib.sh b/install/_lib.sh index 3a76d8624f0..73ef0237df9 100644 --- a/install/_lib.sh +++ b/install/_lib.sh @@ -16,8 +16,16 @@ else _ENV=.env fi +# Reading .env.custom has to come first. The value won't be overriden, instead +# it would persist because of `export -p> >"$t"` later, which exports current +# environment variables to a temporary file with a `declare -x KEY=value` format. +# The new values on `.env` would be set only if they are not already set. +if [[ "$_ENV" == ".env.custom" ]]; then + q=$(mktemp) && export -p >"$q" && set -a && . ".env.custom" && set +a && . "$q" && rm "$q" && unset q +fi + # Read .env for default values with a tip o' the hat to https://stackoverflow.com/a/59831605/90297 -t=$(mktemp) && export -p >"$t" && set -a && . $_ENV && set +a && . "$t" && rm "$t" && unset t +t=$(mktemp) && export -p >"$t" && set -a && . ".env" && set +a && . "$t" && rm "$t" && unset t if [ "${GITHUB_ACTIONS:-}" = "true" ]; then _group="::group::" From 3de8662160e8706a614638f50180d960331170d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:09:45 -0800 Subject: [PATCH 128/305] build(deps): bump actions/create-github-app-token from 1.11.2 to 1.11.3 (#3569) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1.11.2 to 1.11.3. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/136412a57a7081aa63c935a2cc2918f76c34f514...67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1b3f442263f..978be3c9a62 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2 + uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From bc716095e409f7cb096b8bd55ed899b8e3727d49 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sat, 15 Feb 2025 18:05:45 +0000 Subject: [PATCH 129/305] release: 25.2.0 --- .env | 10 +++++----- CHANGELOG.md | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 5688114306b..d44d5d5ab2f 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.2.0 +SNUBA_IMAGE=getsentry/snuba:25.2.0 +RELAY_IMAGE=getsentry/relay:25.2.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.2.0 +VROOM_IMAGE=getsentry/vroom:25.2.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6da8315bbf3..29741bb05c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 25.2.0 + +### Various fixes & improvements + +- build(deps): bump actions/create-github-app-token from 1.11.2 to 1.11.3 (#3569) by @dependabot +- feat: merge `.env` and `.env.custom` file during installation (#3564) by @aldy505 +- build(deps): bump actions/create-github-app-token from 1.11.1 to 1.11.2 (#3561) by @dependabot +- feat: Require both inputs to be set on action (#3554) by @BYK +- ref: Simpler and more accurate cache keys (#3553) by @BYK +- Hand off open-source to dev-infra (#3549) by @chadwhitacre +- ci: Remove obsolete `dcr up -w` from import test (#3544) by @BYK +- fix: github.action_path may not have trailing slash (#3547) by @BYK +- chore: Remove upgrade test (#3541) by @hubertdeng123 +- fix: Use correct path for get compose action (#3539) by @hubertdeng123 +- fix: Caching of sentry migrations should cover additional folders (#3542) by @hubertdeng123 +- ci: Move self-contained action reference to master branch (#3538) by @BYK +- breaking: Upgrade min Compose version to 2.23.2 (#3535) by @BYK +- ci: Even better cache keys and granular caching (#3534) by @BYK +- test: Reorganize backup/restore tests for speed and reliability (#3537) by @BYK + ## 25.1.0 ### Various fixes & improvements From 2f2631840a3cbe9dd8fdbac45abe44f5021b3b34 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 18 Feb 2025 19:52:58 +0000 Subject: [PATCH 130/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index d44d5d5ab2f..5688114306b 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.2.0 -SNUBA_IMAGE=getsentry/snuba:25.2.0 -RELAY_IMAGE=getsentry/relay:25.2.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.2.0 -VROOM_IMAGE=getsentry/vroom:25.2.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 3e1ebfb4fcb087d40f87339fd1a502780b66782a Mon Sep 17 00:00:00 2001 From: leeoocca <36135198+leeoocca@users.noreply.github.com> Date: Fri, 28 Feb 2025 12:32:25 +0100 Subject: [PATCH 131/305] refactor: move system.url-prefix under systems settings section (#3588) --- sentry/config.example.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sentry/config.example.yml b/sentry/config.example.yml index d5a6dc322ce..0764183a199 100644 --- a/sentry/config.example.yml +++ b/sentry/config.example.yml @@ -45,6 +45,10 @@ mail.host: 'smtp' # System Settings # ################### +# The URL prefix in which Sentry is accessible +# system.url-prefix: https://example.sentry.com +system.internal-url-prefix: 'http://web:9000' + # If this file ever becomes compromised, it's important to generate a new key. # Changing this value will result in all current sessions being invalidated. # A new key can be generated with `$ sentry config generate-secret-key` @@ -79,9 +83,6 @@ releasefile.cache-path: '/data/releasefile-cache' # secret_key: 'XXXXXXX' # bucket_name: 's3-bucket-name' -# The URL prefix in which Sentry is accessible -# system.url-prefix: https://example.sentry.com -system.internal-url-prefix: 'http://web:9000' symbolicator.enabled: true symbolicator.options: url: "http://symbolicator:3021" From e883f21b33a54d83342a5bc73eaef63fab27079d Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Mon, 3 Mar 2025 00:34:37 +0330 Subject: [PATCH 132/305] Bump docker-compose 2.33.1 (#3597) Merging to get things green --- get-compose-action/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/get-compose-action/action.yaml b/get-compose-action/action.yaml index 17d5993e70d..7fac08d3489 100644 --- a/get-compose-action/action.yaml +++ b/get-compose-action/action.yaml @@ -2,7 +2,7 @@ name: "Get Docker Compose" inputs: version: required: false - default: 2.32.3 + default: 2.33.1 description: "Docker Compose version" runs: From ab0df5a91e1c21fb6f8192ef44e1de7492b235b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:28:56 +0100 Subject: [PATCH 133/305] build(deps): bump getsentry/action-release from 1 to 3 (#3599) Bumps [getsentry/action-release](https://github.com/getsentry/action-release) from 1 to 3. - [Release notes](https://github.com/getsentry/action-release/releases) - [Changelog](https://github.com/getsentry/action-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/getsentry/action-release/compare/v1...v3) --- updated-dependencies: - dependency-name: getsentry/action-release dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 978be3c9a62..6afafad076d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: getsentry/action-release@v1 + - uses: getsentry/action-release@v3 env: SENTRY_ORG: self-hosted SENTRY_PROJECT: installer From 9b6c1cf6587f4ed699245c68532a4bb07cad8507 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:36:24 +0000 Subject: [PATCH 134/305] build(deps): bump actions/create-github-app-token from 1.11.3 to 1.11.6 (#3598) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1.11.3 to 1.11.6. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7...21cfef2b496dd8ef5b904c159339626a10ad380e) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6afafad076d..d38758b8c9e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3 + uses: actions/create-github-app-token@21cfef2b496dd8ef5b904c159339626a10ad380e # v1.11.6 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From d885dd331ff1991b95d285969ef2bca5add94ce0 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Mon, 3 Mar 2025 16:46:31 +0330 Subject: [PATCH 135/305] Use docker-compose if version is gte docker compose (#3595) Fixes #3587 This PR tries to use docker-compose if its version is greater than docker compose. --- install/_lib.sh | 6 ++++++ install/check-minimum-requirements.sh | 12 ------------ install/dc-detect-version.sh | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/install/_lib.sh b/install/_lib.sh index 73ef0237df9..ee7bb435203 100644 --- a/install/_lib.sh +++ b/install/_lib.sh @@ -53,6 +53,12 @@ function ensure_file_from_example { fi } +# Check the version of $1 is greater than or equal to $2 using sort. Note: versions must be stripped of "v" +function vergte() { + printf "%s\n%s" $1 $2 | sort --version-sort --check=quiet --reverse + echo $? +} + SENTRY_CONFIG_PY=sentry/sentry.conf.py SENTRY_CONFIG_YML=sentry/config.yml diff --git a/install/check-minimum-requirements.sh b/install/check-minimum-requirements.sh index 47848cc2859..fa275882721 100644 --- a/install/check-minimum-requirements.sh +++ b/install/check-minimum-requirements.sh @@ -2,12 +2,6 @@ echo "${_group}Checking minimum requirements ..." source install/_min-requirements.sh -# Check the version of $1 is greater than or equal to $2 using sort. Note: versions must be stripped of "v" -function vergte() { - printf "%s\n%s" $1 $2 | sort --version-sort --check=quiet --reverse - echo $? -} - DOCKER_VERSION=$(docker version --format '{{.Server.Version}}' || echo '') if [[ -z "$DOCKER_VERSION" ]]; then echo "FAIL: Unable to get docker version, is the docker daemon running?" @@ -20,12 +14,6 @@ if [[ "$(vergte ${DOCKER_VERSION//v/} $MIN_DOCKER_VERSION)" -eq 1 ]]; then fi echo "Found Docker version $DOCKER_VERSION" -COMPOSE_VERSION=$($dc_base version --short || echo '') -if [[ -z "$COMPOSE_VERSION" ]]; then - echo "FAIL: Docker compose is required to run self-hosted" - exit 1 -fi - if [[ "$(vergte ${COMPOSE_VERSION//v/} $MIN_COMPOSE_VERSION)" -eq 1 ]]; then echo "FAIL: Expected minimum $dc_base version to be $MIN_COMPOSE_VERSION but found $COMPOSE_VERSION" exit 1 diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index ccee1b5eebe..a27dd7b84a6 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -10,6 +10,23 @@ echo "${_group}Initializing Docker Compose ..." # To support users that are symlinking to docker-compose dc_base="$(docker compose version &>/dev/null && echo 'docker compose' || echo 'docker-compose')" +dc_base_standalone="$(docker-compose version &>/dev/null && echo 'docker-compose' || echo '')" + +COMPOSE_VERSION=$($dc_base version --short || echo '') +STANDALONE_COMPOSE_VERSION=$($dc_base_standalone version --short &>/dev/null || echo '') + +if [[ -z "$COMPOSE_VERSION" && -z "$STANDALONE_COMPOSE_VERSION" ]]; then + echo "FAIL: Docker Compose is required to run self-hosted" + exit 1 +fi + +if [[ ! -z "${STANDALONE_COMPOSE_VERSION}" ]]; then + if [[ "$(vergte ${COMPOSE_VERSION//v/} ${STANDALONE_COMPOSE_VERSION//v/})" -eq 1 ]]; then + COMPOSE_VERSION="${STANDALONE_COMPOSE_VERSION}" + dc_base="$dc_base_standalone" + fi +fi + if [[ "$(basename $0)" = "install.sh" ]]; then dc="$dc_base --ansi never --env-file ${_ENV}" else From e86d18514597b27784bb86a6df3fc5e4ef4ce119 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Wed, 5 Mar 2025 20:25:50 +0000 Subject: [PATCH 136/305] ref: Less complicated docker compose detection (#3604) With #3595, we now check both `docker-compose` and `docker compose` versions so this patch removes the implicit fallback to `docker-compose` for `$dc_base` and makes it explicit. --- install/dc-detect-version.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index a27dd7b84a6..9d52a42ad7b 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -9,22 +9,20 @@ fi echo "${_group}Initializing Docker Compose ..." # To support users that are symlinking to docker-compose -dc_base="$(docker compose version &>/dev/null && echo 'docker compose' || echo 'docker-compose')" +dc_base="$(docker compose version --short &>/dev/null && echo 'docker compose' || echo '')" dc_base_standalone="$(docker-compose version &>/dev/null && echo 'docker-compose' || echo '')" -COMPOSE_VERSION=$($dc_base version --short || echo '') -STANDALONE_COMPOSE_VERSION=$($dc_base_standalone version --short &>/dev/null || echo '') +COMPOSE_VERSION=$([ -n "$dc_base" ] && $dc_base version --short || echo '') +STANDALONE_COMPOSE_VERSION=$([ -n "$dc_base_standalone" ] && $dc_base_standalone version --short &>/dev/null || echo '') if [[ -z "$COMPOSE_VERSION" && -z "$STANDALONE_COMPOSE_VERSION" ]]; then echo "FAIL: Docker Compose is required to run self-hosted" exit 1 fi -if [[ ! -z "${STANDALONE_COMPOSE_VERSION}" ]]; then - if [[ "$(vergte ${COMPOSE_VERSION//v/} ${STANDALONE_COMPOSE_VERSION//v/})" -eq 1 ]]; then - COMPOSE_VERSION="${STANDALONE_COMPOSE_VERSION}" - dc_base="$dc_base_standalone" - fi +if [[ -z "$COMPOSE_VERSION" || -n "$STANDALONE_COMPOSE_VERSION" && "$(vergte ${COMPOSE_VERSION//v/} ${STANDALONE_COMPOSE_VERSION//v/})" -eq 1 ]]; then + COMPOSE_VERSION="${STANDALONE_COMPOSE_VERSION}" + dc_base="$dc_base_standalone" fi if [[ "$(basename $0)" = "install.sh" ]]; then From d08a6d9b668358957b7dd7712ba08a1b08aa00f8 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Thu, 6 Mar 2025 14:15:47 +0330 Subject: [PATCH 137/305] Add --short to docker-compose version (#3605) --- install/dc-detect-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index 9d52a42ad7b..ff4c9f82bf8 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -10,7 +10,7 @@ echo "${_group}Initializing Docker Compose ..." # To support users that are symlinking to docker-compose dc_base="$(docker compose version --short &>/dev/null && echo 'docker compose' || echo '')" -dc_base_standalone="$(docker-compose version &>/dev/null && echo 'docker-compose' || echo '')" +dc_base_standalone="$(docker-compose version --short &>/dev/null && echo 'docker-compose' || echo '')" COMPOSE_VERSION=$([ -n "$dc_base" ] && $dc_base version --short || echo '') STANDALONE_COMPOSE_VERSION=$([ -n "$dc_base_standalone" ] && $dc_base_standalone version --short &>/dev/null || echo '') From 979f219355c5022cabb022be5b6daa53c2a32af9 Mon Sep 17 00:00:00 2001 From: Brett Higgins Date: Thu, 6 Mar 2025 05:46:16 -0500 Subject: [PATCH 138/305] Fix unbound variable error in install script (#3601) --- install/_lib.sh | 1 - install/check-minimum-requirements.sh | 4 ++-- install/dc-detect-version.sh | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/install/_lib.sh b/install/_lib.sh index ee7bb435203..e4ce0aaaa4f 100644 --- a/install/_lib.sh +++ b/install/_lib.sh @@ -56,7 +56,6 @@ function ensure_file_from_example { # Check the version of $1 is greater than or equal to $2 using sort. Note: versions must be stripped of "v" function vergte() { printf "%s\n%s" $1 $2 | sort --version-sort --check=quiet --reverse - echo $? } SENTRY_CONFIG_PY=sentry/sentry.conf.py diff --git a/install/check-minimum-requirements.sh b/install/check-minimum-requirements.sh index fa275882721..e06db42c48a 100644 --- a/install/check-minimum-requirements.sh +++ b/install/check-minimum-requirements.sh @@ -8,13 +8,13 @@ if [[ -z "$DOCKER_VERSION" ]]; then exit 1 fi -if [[ "$(vergte ${DOCKER_VERSION//v/} $MIN_DOCKER_VERSION)" -eq 1 ]]; then +if ! vergte ${DOCKER_VERSION//v/} $MIN_DOCKER_VERSION; then echo "FAIL: Expected minimum docker version to be $MIN_DOCKER_VERSION but found $DOCKER_VERSION" exit 1 fi echo "Found Docker version $DOCKER_VERSION" -if [[ "$(vergte ${COMPOSE_VERSION//v/} $MIN_COMPOSE_VERSION)" -eq 1 ]]; then +if ! vergte ${COMPOSE_VERSION//v/} $MIN_COMPOSE_VERSION; then echo "FAIL: Expected minimum $dc_base version to be $MIN_COMPOSE_VERSION but found $COMPOSE_VERSION" exit 1 fi diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index ff4c9f82bf8..6f1b1df1a5d 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -20,7 +20,7 @@ if [[ -z "$COMPOSE_VERSION" && -z "$STANDALONE_COMPOSE_VERSION" ]]; then exit 1 fi -if [[ -z "$COMPOSE_VERSION" || -n "$STANDALONE_COMPOSE_VERSION" && "$(vergte ${COMPOSE_VERSION//v/} ${STANDALONE_COMPOSE_VERSION//v/})" -eq 1 ]]; then +if [[ -z "$COMPOSE_VERSION" ]] || [[ -n "$STANDALONE_COMPOSE_VERSION" ]] && ! vergte ${COMPOSE_VERSION//v/} ${STANDALONE_COMPOSE_VERSION//v/}; then COMPOSE_VERSION="${STANDALONE_COMPOSE_VERSION}" dc_base="$dc_base_standalone" fi From 4fff2e39df69bf6556d0df462c3a57c6d4c8c2c9 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Thu, 6 Mar 2025 14:24:25 +0330 Subject: [PATCH 139/305] Enforce license compliance only on getsentry repository (#3606) It fails every time and it isn't needed. https://github.com/aminvakil/self-hosted/actions/runs/13685684000 ### Legal Boilerplate Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. --- .github/workflows/enforce-license-compliance.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/enforce-license-compliance.yml b/.github/workflows/enforce-license-compliance.yml index 46d724d32c4..02ca9d8e3f6 100644 --- a/.github/workflows/enforce-license-compliance.yml +++ b/.github/workflows/enforce-license-compliance.yml @@ -8,6 +8,7 @@ on: jobs: enforce-license-compliance: + if: github.repository_owner == 'getsentry' runs-on: ubuntu-latest steps: - name: 'Enforce License Compliance' From 9486a832eb80cb2833ea6fa0cbef60c4f1a2bfa9 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 10 Mar 2025 20:44:40 +0000 Subject: [PATCH 140/305] feat: provide monitoring-related configurations (#3611) In accordance with https://github.com/getsentry/sentry-docs/pull/12660 --- docker-compose.yml | 4 ++++ relay/config.example.yml | 11 +++++++++++ sentry/sentry.conf.example.py | 18 ++++++++++++++++++ symbolicator/config.example.yml | 7 +++++++ 4 files changed, 40 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 9d8ee5a9e4c..75a86e2e59b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -84,6 +84,10 @@ x-snuba-defaults: &snuba_defaults # Leaving the value empty to just pass whatever is set # on the host system (or in the .env file) SENTRY_EVENT_RETENTION_DAYS: + # If you have statsd server, you can utilize that to monitor self-hosted Snuba containers. + # To start, state these environment variables below on your `.env.` file and adjust the options as needed. + SNUBA_STATSD_HOST: # Example value: "100.100.123.123". Must be an IP address, not domain name + SNUBA_STATSD_PORT: # Example value: 8125 services: smtp: <<: *restart_policy diff --git a/relay/config.example.yml b/relay/config.example.yml index f73e45acca8..f1a239de495 100644 --- a/relay/config.example.yml +++ b/relay/config.example.yml @@ -18,3 +18,14 @@ processing: # # health: # max_memory_percent: 1.0 + +# If you have statsd server, you can utilize that to monitor self-hosted Relay. +# To start, uncomment the following line and adjust the options as needed. +# +# metrics: +# statsd: "100.100.123.123:8125" # It is recommended to use IP address instead of domain name +# prefix: "sentry.relay" # Adjust this to your needs, default is "sentry.relay" +# sample_rate: 1.0 # Adjust this to your needs, default is 1.0 +# # `periodic_secs` is the interval for periodic metrics emitted from Relay. +# # Setting it to `0` seconds disables the periodic metrics. +# periodic_secs: 5 diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 98e7a6c0fb3..78bd392d116 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -396,3 +396,21 @@ def get_internal_network(): # to allow specific hosts. It might be IP addresses or domain names (without `http://` or `https://`). # SENTRY_OPTIONS["relay.span-normalization.allowed_hosts"] = ["example.com", "192.168.10.1"] + +############## +# Monitoring # +############## + +# By default, Sentry uses dummy statsd monitoring backend that is a no-op. +# If you have a statsd server, you can utilize that to monitor self-hosted +# Sentry for "sentry"-related containers. +# +# To start, uncomment the following line and adjust the options as needed. + +# SENTRY_METRICS_BACKEND = 'sentry.metrics.statsd.StatsdMetricsBackend' +# SENTRY_METRICS_OPTIONS: dict[str, Any] = { +# 'host': '100.100.123.123', # It is recommended to use IP address instead of domain name +# 'port': 8125, +# } +# SENTRY_METRICS_SAMPLE_RATE = 1.0 # Adjust this to your needs, default is 1.0 +# SENTRY_METRICS_PREFIX = "sentry." # Adjust this to your needs, default is "sentry." diff --git a/symbolicator/config.example.yml b/symbolicator/config.example.yml index 62cf9b83b70..de716de8c4c 100644 --- a/symbolicator/config.example.yml +++ b/symbolicator/config.example.yml @@ -6,3 +6,10 @@ logging: metrics: statsd: null sentry_dsn: null # TODO: Automatically fill this with the internal project DSN + +# If you have statsd server, you can utilize that to monitor self-hosted Symbolicator. +# To start, uncomment the following line and adjust the options as needed. +# +# metrics: +# statsd: "100.100.123.123:8125" # It is recommended to use IP address instead of domain name +# prefix: "sentry.symbolicator" # Adjust this to your needs, default is "symbolicator" From 30f8d0125f919e2cfef2b47edf80a9b0611b74c6 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 14 Mar 2025 13:46:30 +0000 Subject: [PATCH 141/305] feat(features): enable trace view (#3617) --- sentry/sentry.conf.example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 78bd392d116..121ac58bb13 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -298,6 +298,7 @@ def get_internal_network(): "organizations:dashboards-rh-widget", "organizations:metrics-extraction", "organizations:transaction-metrics-extraction", + "organizations:trace-view-v1", "projects:custom-inbound-filters", "projects:data-forwarding", "projects:discard-groups", From 09532da147cd032fa36f6634d56d27897308e1ea Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sat, 15 Mar 2025 18:05:53 +0000 Subject: [PATCH 142/305] release: 25.3.0 --- .env | 10 +++++----- CHANGELOG.md | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 5688114306b..df49ce13784 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.3.0 +SNUBA_IMAGE=getsentry/snuba:25.3.0 +RELAY_IMAGE=getsentry/relay:25.3.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.3.0 +VROOM_IMAGE=getsentry/vroom:25.3.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 29741bb05c4..202a7b2186d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 25.3.0 + +### Various fixes & improvements + +- feat(features): enable trace view (#3617) by @aldy505 +- feat: provide monitoring-related configurations (#3611) by @aldy505 +- Enforce license compliance only on getsentry repository (#3606) by @aminvakil +- Fix unbound variable error in install script (#3601) by @brettdh +- Add --short to docker-compose version (#3605) by @aminvakil +- ref: Less complicated docker compose detection (#3604) by @BYK +- Use docker-compose if version is gte docker compose (#3595) by @aminvakil +- build(deps): bump actions/create-github-app-token from 1.11.3 to 1.11.6 (#3598) by @dependabot +- build(deps): bump getsentry/action-release from 1 to 3 (#3599) by @dependabot +- Bump docker-compose 2.33.1 (#3597) by @aminvakil +- refactor: move system.url-prefix under systems settings section (#3588) by @leeoocca + ## 25.2.0 ### Various fixes & improvements From d63138d8b70a33c7109cb7926718834abe119403 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 17 Mar 2025 14:33:46 +0000 Subject: [PATCH 143/305] feat(features): enable session replay canvas (#3619) --- sentry/sentry.conf.example.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 121ac58bb13..83fe144d896 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -290,6 +290,8 @@ def get_internal_network(): "organizations:performance-view", "organizations:advanced-search", "organizations:session-replay", + "organizations:session-replay-enable-canvas", + "organizations:session-replay-enable-canvas-replayer", "organizations:issue-platform", "organizations:profiling", "organizations:monitors", From b0c3090b176f31779dfd20d43036b94db2f86001 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 17 Mar 2025 17:39:00 +0000 Subject: [PATCH 144/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index df49ce13784..5688114306b 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.3.0 -SNUBA_IMAGE=getsentry/snuba:25.3.0 -RELAY_IMAGE=getsentry/relay:25.3.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.3.0 -VROOM_IMAGE=getsentry/vroom:25.3.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From d350bd4b7d14b51df2db1782ccae3655732c4143 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 18 Mar 2025 12:26:48 +0000 Subject: [PATCH 145/305] fix: js-sdk directory/file permission should be set correctly (#3616) --- _unit-test/js-sdk-assets-test.sh | 13 ++++++++++--- install/setup-js-sdk-assets.sh | 10 ++++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/_unit-test/js-sdk-assets-test.sh b/_unit-test/js-sdk-assets-test.sh index bd898acf6a7..7e2306ecb97 100755 --- a/_unit-test/js-sdk-assets-test.sh +++ b/_unit-test/js-sdk-assets-test.sh @@ -20,14 +20,21 @@ echo $total_directories test "5" == "$total_directories" echo "Pass" -# `sdk_tree` should output "5 directories, 17 files" +# `sdk_tree` should output "6 directories, 23 files" echo "$sdk_tree" -test "5 directories, 17 files" == "$(echo "$sdk_tree")" +test "6 directories, 23 files" == "$(echo "$sdk_tree")" echo "Pass" # Files should all be >1k (ensure they are not empty) echo "Testing file sizes" -test "17" == "$non_empty_file_count" +test "23" == "$non_empty_file_count" +echo "Pass" + +# Files should be owned by the root user +echo "Testing file ownership" +directory_owners=$(echo "$sdk_files" | awk '$3=="root" { print $0 }' | wc -l) +echo "$directory_owners" +test "$directory_owners" == "8" echo "Pass" report_success diff --git a/install/setup-js-sdk-assets.sh b/install/setup-js-sdk-assets.sh index 50b9428dd4b..51c5e408191 100644 --- a/install/setup-js-sdk-assets.sh +++ b/install/setup-js-sdk-assets.sh @@ -27,14 +27,20 @@ if [[ "${SETUP_JS_SDK_ASSETS:-}" == "1" ]]; then latest_js_v6=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("6.")))) | .[0]') latest_js_v7=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("7.")))) | .[0]') latest_js_v8=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("8.")))) | .[0]') + latest_js_v9=$(echo "$loader_registry" | $jq -r '.versions | reverse | map(select(.|any(.; startswith("9.")))) | .[0]') - echo "Found JS SDKs: v${latest_js_v4}, v${latest_js_v5}, v${latest_js_v6}, v${latest_js_v7}, v${latest_js_v8}" + echo "Found JS SDKs: v${latest_js_v4}, v${latest_js_v5}, v${latest_js_v6}, v${latest_js_v7}, v${latest_js_v8}, v${latest_js_v9}" - versions="{$latest_js_v4,$latest_js_v5,$latest_js_v6,$latest_js_v7,$latest_js_v8}" + versions="{$latest_js_v4,$latest_js_v5,$latest_js_v6,$latest_js_v7,$latest_js_v8,$latest_js_v9}" variants="{bundle,bundle.tracing,bundle.tracing.replay,bundle.replay,bundle.tracing.replay.feedback,bundle.feedback}" # Download those versions & variants using curl $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx curl -w '%{response_code} %{url}\n' --no-progress-meter --compressed --retry 3 --create-dirs -fLo "/var/www/js-sdk/#1/#2.min.js" "https://browser.sentry-cdn.com/${versions}/${variants}.min.js" || true + # Make sure permissions are correct + # See https://github.com/getsentry/self-hosted/issues/3614 for reported issue + $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx find /var/www/js-sdk -type d -exec chmod 755 {} \; + $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx find /var/www/js-sdk -type f -exec chmod 644 {} \; + echo "${_endgroup}" fi From 1c3047fa8fdfe0dfc6916ae610f3f56500abf685 Mon Sep 17 00:00:00 2001 From: Junsung Cho <97071544+junsung-cho@users.noreply.github.com> Date: Tue, 18 Mar 2025 21:35:07 +0900 Subject: [PATCH 146/305] docs(config): add example config for Google Auth (#3623) --- sentry/config.example.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sentry/config.example.yml b/sentry/config.example.yml index 0764183a199..54fe0c9c813 100644 --- a/sentry/config.example.yml +++ b/sentry/config.example.yml @@ -133,3 +133,12 @@ transaction-events.force-disable-internal-project: true # discord.public-key: "" # discord.client-secret: "" # discord.bot-token: "" + +############### +# Google Auth # +############### + +# Refer to https://develop.sentry.dev/self-hosted/sso/#google-auth + +# auth-google.client-id: "" +# auth-google.client-secret: "" From 0970b144f582b2008635631c8f95ef5e1e89b9b7 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 24 Mar 2025 14:09:06 +0000 Subject: [PATCH 147/305] feat(sentry): add dynamic sampling feature to config (#3631) --- sentry/sentry.conf.example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 83fe144d896..b1d5a8daef5 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -301,6 +301,7 @@ def get_internal_network(): "organizations:metrics-extraction", "organizations:transaction-metrics-extraction", "organizations:trace-view-v1", + "organizations:dynamic-sampling", "projects:custom-inbound-filters", "projects:data-forwarding", "projects:discard-groups", From c32836714d736dae6db3ba9c38e6beb82735a90a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 14:14:17 +0000 Subject: [PATCH 148/305] build(deps): bump actions/create-github-app-token from 1.11.6 to 1.11.7 (#3632) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1.11.6 to 1.11.7. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/21cfef2b496dd8ef5b904c159339626a10ad380e...af35edadc00be37caa72ed9f3e6d5f7801bfdf09) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d38758b8c9e..390ac8e7580 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@21cfef2b496dd8ef5b904c159339626a10ad380e # v1.11.6 + uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1.11.7 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From ae05091f9ff55c664ef453d121fe5c89c48a4b9d Mon Sep 17 00:00:00 2001 From: Kliachin Aleksei Date: Thu, 27 Mar 2025 12:14:02 +0300 Subject: [PATCH 149/305] Minimum requirements for 'errors-only' profile (#3634) Using the [errors-only](https://develop.sentry.dev/self-hosted/experimental/errors-only/) profile, fewer resources are required. About 2 times. --- install/_min-requirements.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/install/_min-requirements.sh b/install/_min-requirements.sh index c518508e2f3..17afa00995d 100644 --- a/install/_min-requirements.sh +++ b/install/_min-requirements.sh @@ -4,6 +4,10 @@ MIN_COMPOSE_VERSION='2.32.2' # 16 GB minimum host RAM, but there'll be some overhead outside of what # can be allotted to docker -MIN_RAM_HARD=14000 # MB - -MIN_CPU_HARD=4 +if [[ "$COMPOSE_PROFILES" == "errors-only" ]]; then + MIN_RAM_HARD=7000 # MB + MIN_CPU_HARD=2 +else + MIN_RAM_HARD=14000 # MB + MIN_CPU_HARD=4 +fi From b2819cdac13baa04e6212d0551ed718a79227bb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 09:09:52 +0300 Subject: [PATCH 150/305] build(deps): bump actions/create-github-app-token from 1.11.7 to 1.12.0 (#3639) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1.11.7 to 1.12.0. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/af35edadc00be37caa72ed9f3e6d5f7801bfdf09...d72941d797fd3113feb6b93fd0dec494b13a2547) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 390ac8e7580..d07dd657304 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@af35edadc00be37caa72ed9f3e6d5f7801bfdf09 # v1.11.7 + uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From 53412bbefbc09a076a0beb52c10efa0589a6b52e Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Sat, 12 Apr 2025 18:59:38 +0330 Subject: [PATCH 151/305] Fix STANDALONE_COMPOSE_VERSION variable setting (#3654) --- install/dc-detect-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index 6f1b1df1a5d..16297363362 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -13,7 +13,7 @@ dc_base="$(docker compose version --short &>/dev/null && echo 'docker compose' | dc_base_standalone="$(docker-compose version --short &>/dev/null && echo 'docker-compose' || echo '')" COMPOSE_VERSION=$([ -n "$dc_base" ] && $dc_base version --short || echo '') -STANDALONE_COMPOSE_VERSION=$([ -n "$dc_base_standalone" ] && $dc_base_standalone version --short &>/dev/null || echo '') +STANDALONE_COMPOSE_VERSION=$([ -n "$dc_base_standalone" ] && $dc_base_standalone version --short || echo '') if [[ -z "$COMPOSE_VERSION" && -z "$STANDALONE_COMPOSE_VERSION" ]]; then echo "FAIL: Docker Compose is required to run self-hosted" From 6b4487f032e53a7e18217501956c133b2859e7f1 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Sat, 12 Apr 2025 19:00:25 +0330 Subject: [PATCH 152/305] Use dc variable in clickhouse step (#3658) --- install/upgrade-clickhouse.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/upgrade-clickhouse.sh b/install/upgrade-clickhouse.sh index bd69d7bf746..3dcb56f189c 100644 --- a/install/upgrade-clickhouse.sh +++ b/install/upgrade-clickhouse.sh @@ -1,7 +1,7 @@ echo "${_group}Upgrading Clickhouse ..." # First check to see if user is upgrading by checking for existing clickhouse volume -if docker compose ps -a | grep -q clickhouse; then +if $dc ps -a | grep -q clickhouse; then # Start clickhouse if it is not already running $dc up --wait clickhouse From a956339180f3ce06ffec59a83594eafc231a4a7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Apr 2025 18:32:35 +0300 Subject: [PATCH 153/305] build(deps): bump actions/create-github-app-token from 1.12.0 to 2.0.2 (#3649) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1.12.0 to 2.0.2. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/d72941d797fd3113feb6b93fd0dec494b13a2547...3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 2.0.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d07dd657304..3a72ed938f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 + uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From 054b9155f0ae1b88dc4f5095231b014b6a8ff252 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 12 Apr 2025 15:42:08 +0000 Subject: [PATCH 154/305] chore(relay): specify spool.enveloppe.max_backpressure_memory_percent configuration for handling relay's failing healthcheck (#3635) * chore(relay): specify spool.enveloppe.max_backpressure_memory_percent configuration for handling relay's failing healthcheck Although a fix is being rolled out, that does not mean every relay instance would suddenly be fixed. We would need to still provide a workaround for people to try out. Refer to this specific issue comment: https://github.com/getsentry/self-hosted/issues/3330#issuecomment-2751092219 * Update config.example.yml Co-authored-by: Riccardo Busetti * chore: default path for relay spool envelopes --------- Co-authored-by: Riccardo Busetti --- relay/config.example.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/relay/config.example.yml b/relay/config.example.yml index f1a239de495..06c73079564 100644 --- a/relay/config.example.yml +++ b/relay/config.example.yml @@ -14,13 +14,18 @@ processing: # In some cases, relay might fail to find out the actual machine memory # therefore it makes the healthcheck fail and events can't be submitted. -# As a workaround, uncomment the following line: +# See https://github.com/getsentry/self-hosted/issues/3330 for more details. +# As a workaround, uncomment the following `health` and `spool` sections: # # health: # max_memory_percent: 1.0 +# spool: +# envelopes: +# path: "/tmp/relay-spool-envelopes" +# max_backpressure_memory_percent: 1.0 # If you have statsd server, you can utilize that to monitor self-hosted Relay. -# To start, uncomment the following line and adjust the options as needed. +# To start, uncomment the following `metrics` section and adjust the options as needed. # # metrics: # statsd: "100.100.123.123:8125" # It is recommended to use IP address instead of domain name From 36d8b2c6b2571d3f36a8bf7508b5bd57740bd4f2 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 15 Apr 2025 18:06:13 +0000 Subject: [PATCH 155/305] release: 25.4.0 --- .env | 10 +++++----- CHANGELOG.md | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 5688114306b..6eb15751fa6 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.4.0 +SNUBA_IMAGE=getsentry/snuba:25.4.0 +RELAY_IMAGE=getsentry/relay:25.4.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.4.0 +VROOM_IMAGE=getsentry/vroom:25.4.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 202a7b2186d..b5236ce1d4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 25.4.0 + +### Stand-alone Docker Compose Fixes + +By: @aminvakil (#3658, #3654) + +### Various fixes & improvements + +- chore(relay): specify spool.enveloppe.max_backpressure_memory_percent configuration for handling relay's failing healthcheck (#3635) by @aldy505 +- build(deps): bump actions/create-github-app-token from 1.12.0 to 2.0.2 (#3649) by @dependabot +- build(deps): bump actions/create-github-app-token from 1.11.7 to 1.12.0 (#3639) by @dependabot +- Minimum requirements for 'errors-only' profile (#3634) by @madest92 +- build(deps): bump actions/create-github-app-token from 1.11.6 to 1.11.7 (#3632) by @dependabot +- feat(sentry): add dynamic sampling feature to config (#3631) by @aldy505 +- docs(config): add example config for Google Auth (#3623) by @junsung-cho +- fix: js-sdk directory/file permission should be set correctly (#3616) by @aldy505 +- feat(features): enable session replay canvas (#3619) by @aldy505 + ## 25.3.0 ### Various fixes & improvements From 92b419b551e8e6b0da2561d480fb8b02b98488e7 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 15 Apr 2025 22:13:08 +0000 Subject: [PATCH 156/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 6eb15751fa6..5688114306b 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.4.0 -SNUBA_IMAGE=getsentry/snuba:25.4.0 -RELAY_IMAGE=getsentry/relay:25.4.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.4.0 -VROOM_IMAGE=getsentry/vroom:25.4.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 241b58dd2229a4f3837286ffe6e05918b50729ac Mon Sep 17 00:00:00 2001 From: anthony sottile <103459774+asottile-sentry@users.noreply.github.com> Date: Thu, 1 May 2025 13:18:23 -0400 Subject: [PATCH 157/305] ref: remove SENTRY_USE_BIG_INTS (always True) (#3687) --- sentry/sentry.conf.example.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index b1d5a8daef5..d97b50b9ce8 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -53,10 +53,6 @@ def get_internal_network(): } } -# You should not change this setting after your database has been created -# unless you have altered all schemas first -SENTRY_USE_BIG_INTS = True - # If you're expecting any kind of real traffic on Sentry, we highly recommend # configuring the CACHES and Redis settings From 84094424e8834002266bfa33ba5fdec75635e6c0 Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Fri, 2 May 2025 14:19:34 +0300 Subject: [PATCH 158/305] Resolve datetime deprecation warnings (#3686) # PR Summary This small PR fixes the `datetime` deprecation warnings which you can find in the CI logs: ```python /home/runner/work/_actions/getsentry/self-hosted/master/_integration-test/test_01_basics.py:303: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). ``` --- _integration-test/test_01_basics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_integration-test/test_01_basics.py b/_integration-test/test_01_basics.py index 110de083855..121aded1b18 100644 --- a/_integration-test/test_01_basics.py +++ b/_integration-test/test_01_basics.py @@ -177,8 +177,8 @@ def test_custom_certificate_authorities(): .issuer_name(ca_name) .public_key(ca_key.public_key()) .serial_number(x509.random_serial_number()) - .not_valid_before(datetime.datetime.utcnow()) - .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=1)) + .not_valid_before(datetime.datetime.now(datetime.timezone.utc)) + .not_valid_after(datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1)) .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True) .add_extension( x509.KeyUsage( From f7b6c03346ecd8eec945e372775cbea356f85b2c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 09:12:26 -0700 Subject: [PATCH 159/305] build(deps): bump actions/create-github-app-token from 2.0.2 to 2.0.6 (#3690) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.0.2 to 2.0.6. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5...df432ceedc7162793a195dd1713ff69aefc7379e) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 2.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3a72ed938f1..d744f50290a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From f183e71bab45a0dd027c9535d7c5e79fe61a9ba7 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 15 May 2025 18:07:10 +0000 Subject: [PATCH 160/305] release: 25.5.0 --- .env | 10 +++++----- CHANGELOG.md | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 5688114306b..629512829c0 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.5.0 +SNUBA_IMAGE=getsentry/snuba:25.5.0 +RELAY_IMAGE=getsentry/relay:25.5.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.5.0 +VROOM_IMAGE=getsentry/vroom:25.5.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index b5236ce1d4a..9286ecbd85c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 25.5.0 + +### Various fixes & improvements + +- build(deps): bump actions/create-github-app-token from 2.0.2 to 2.0.6 (#3690) by @dependabot +- Resolve datetime deprecation warnings (#3686) by @emmanuel-ferdman +- ref: remove SENTRY_USE_BIG_INTS (always True) (#3687) by @asottile-sentry + ## 25.4.0 ### Stand-alone Docker Compose Fixes From b8b0ee80e7b92556202dfc49ef2e7d055d302781 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 15 May 2025 18:50:41 +0000 Subject: [PATCH 161/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 629512829c0..5688114306b 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.5.0 -SNUBA_IMAGE=getsentry/snuba:25.5.0 -RELAY_IMAGE=getsentry/relay:25.5.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.5.0 -VROOM_IMAGE=getsentry/vroom:25.5.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 9e085a0f7891c22a52a90e76f0ced0bcd79ef957 Mon Sep 17 00:00:00 2001 From: Nikita Korolev <66738864+doc-sheet@users.noreply.github.com> Date: Fri, 16 May 2025 12:53:41 +0300 Subject: [PATCH 162/305] chore: cleanup obsolete feature flags (#3701) * remove obsolete SENTRY_RELEASE_HEALTH removed in https://github.com/getsentry/sentry/pull/68226 * remove unused feature flags removed in https://github.com/getsentry/sentry/pull/32010 * remove session-replay-enable-canvas removed in https://github.com/getsentry/sentry/pull/87762 --- sentry/sentry.conf.example.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index d97b50b9ce8..902c393fcf2 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -196,15 +196,6 @@ def get_internal_network(): SENTRY_DIGESTS = "sentry.digests.backends.redis.RedisBackend" -################### -# Metrics Backend # -################### - -SENTRY_RELEASE_HEALTH = "sentry.release_health.metrics.MetricsReleaseHealthBackend" -SENTRY_RELEASE_MONITOR = ( - "sentry.release_health.release_monitor.metrics.MetricReleaseMonitorBackend" -) - ############## # Web Server # ############## @@ -273,21 +264,17 @@ def get_internal_network(): feature: True for feature in ( "organizations:discover", - "organizations:events", "organizations:global-views", "organizations:incidents", "organizations:integrations-issue-basic", "organizations:integrations-issue-sync", "organizations:invite-members", - "organizations:metric-alert-builder-aggregate", "organizations:sso-basic", "organizations:sso-rippling", "organizations:sso-saml2", "organizations:performance-view", "organizations:advanced-search", "organizations:session-replay", - "organizations:session-replay-enable-canvas", - "organizations:session-replay-enable-canvas-replayer", "organizations:issue-platform", "organizations:profiling", "organizations:monitors", From 031a1f10937f3e49219d19474ac2fcb2d1c474a1 Mon Sep 17 00:00:00 2001 From: Dominik Jakielski <52488859+djakielski@users.noreply.github.com> Date: Mon, 19 May 2025 10:24:57 +0200 Subject: [PATCH 163/305] Add missing lib script to sentry-admin.sh (#3693) Sentry Admin Script always fail because of missing import of lib script. ### Legal Boilerplate Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms. --- install.sh | 9 +++++++-- install/_lib.sh | 10 ---------- install/_logging.sh | 3 +++ install/dc-detect-version.sh | 2 +- sentry-admin.sh | 1 + 5 files changed, 12 insertions(+), 13 deletions(-) create mode 100644 install/_logging.sh diff --git a/install.sh b/install.sh index 23726ce97fd..86e4de1b404 100755 --- a/install.sh +++ b/install.sh @@ -1,12 +1,17 @@ #!/usr/bin/env bash -set -eE +set -eEuo pipefail +test "${DEBUG:-}" && set -x + +# Override any user-supplied umask that could cause problems, see #1222 +umask 002 # Pre-pre-flight? 🤷 -if [[ -n "$MSYSTEM" ]]; then +if [[ -n "${MSYSTEM:-}" ]]; then echo "Seems like you are using an MSYS2-based system (such as Git Bash) which is not supported. Please use WSL instead." exit 1 fi +source install/_logging.sh source install/_lib.sh # Pre-flight. No impact yet. diff --git a/install/_lib.sh b/install/_lib.sh index e4ce0aaaa4f..9abbf1a3d3b 100644 --- a/install/_lib.sh +++ b/install/_lib.sh @@ -1,13 +1,3 @@ -set -euo pipefail -test "${DEBUG:-}" && set -x - -# Override any user-supplied umask that could cause problems, see #1222 -umask 002 - -# Thanks to https://unix.stackexchange.com/a/145654/108960 -log_file=sentry_install_log-$(date +'%Y-%m-%d_%H-%M-%S').txt -exec &> >(tee -a "$log_file") - # Allow `.env` overrides using the `.env.custom` file. # We pass this to docker compose in a couple places. if [[ -f .env.custom ]]; then diff --git a/install/_logging.sh b/install/_logging.sh new file mode 100644 index 00000000000..ea529dade98 --- /dev/null +++ b/install/_logging.sh @@ -0,0 +1,3 @@ +# Thanks to https://unix.stackexchange.com/a/145654/108960 +log_file=sentry_install_log-$(date +'%Y-%m-%d_%H-%M-%S').txt +exec &> >(tee -a "$log_file") diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index 16297363362..5acaf59c676 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -34,5 +34,5 @@ proxy_args="--build-arg http_proxy=${http_proxy:-} --build-arg https_proxy=${htt dcr="$dc run --pull=never --rm" dcb="$dc build $proxy_args" dbuild="docker build $proxy_args" - +echo "$dcr" echo "${_endgroup}" diff --git a/sentry-admin.sh b/sentry-admin.sh index 386b3d57011..f90af33c81a 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -4,6 +4,7 @@ cd $(dirname $0) # Detect docker and platform state. +source install/_lib.sh source install/dc-detect-version.sh source install/detect-platform.sh From cbebc4f3f43a6ef5834d059bb144e67b7515d752 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 21 May 2025 15:46:37 +0000 Subject: [PATCH 164/305] release: 25.5.1 --- .env | 10 +++++----- CHANGELOG.md | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 5688114306b..455fc7b0c2c 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.5.1 +SNUBA_IMAGE=getsentry/snuba:25.5.1 +RELAY_IMAGE=getsentry/relay:25.5.1 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.5.1 +VROOM_IMAGE=getsentry/vroom:25.5.1 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9286ecbd85c..d421410f31c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 25.5.1 + +### Various fixes & improvements + +- Add missing lib script to sentry-admin.sh (#3693) by @djakielski +- chore: cleanup obsolete feature flags (#3701) by @doc-sheet + ## 25.5.0 ### Various fixes & improvements From 5173b3197e3f2e19112eb777fd352e520955d506 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 21 May 2025 16:21:20 +0000 Subject: [PATCH 165/305] build: Set master version to nightly #skip-changelog --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 455fc7b0c2c..5688114306b 100644 --- a/.env +++ b/.env @@ -9,11 +9,11 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.5.1 -SNUBA_IMAGE=getsentry/snuba:25.5.1 -RELAY_IMAGE=getsentry/relay:25.5.1 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.5.1 -VROOM_IMAGE=getsentry/vroom:25.5.1 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 4276f44a07fbd3eda25ef5d511ca75b1f1b6be99 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Tue, 27 May 2025 13:07:44 +0200 Subject: [PATCH 166/305] Make usage of Python SDK future proof (#3714) Fixes problems that appear when Python SDK 3.0 will be released. --- _integration-test/test_01_basics.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/_integration-test/test_01_basics.py b/_integration-test/test_01_basics.py index 121aded1b18..741d4fd807c 100644 --- a/_integration-test/test_01_basics.py +++ b/_integration-test/test_01_basics.py @@ -123,8 +123,10 @@ def test_login(client_login): def test_receive_event(client_login): event_id = None client, _ = client_login - with sentry_sdk.init(dsn=get_sentry_dsn(client)): - event_id = sentry_sdk.capture_exception(Exception("a failure")) + + sentry_sdk.init(dsn=get_sentry_dsn(client)) + + event_id = sentry_sdk.capture_exception(Exception("a failure")) assert event_id is not None response = poll_for_response( f"{SENTRY_TEST_HOST}/api/0/projects/sentry/internal/events/{event_id}/", client @@ -377,18 +379,19 @@ def test_custom_certificate_authorities(): def test_receive_transaction_events(client_login): client, _ = client_login - with sentry_sdk.init( + sentry_sdk.init( dsn=get_sentry_dsn(client), profiles_sample_rate=1.0, traces_sample_rate=1.0 - ): + ) + + def placeholder_fn(): + sum = 0 + for i in range(5): + sum += i + time.sleep(0.25) - def placeholder_fn(): - sum = 0 - for i in range(5): - sum += i - time.sleep(0.25) + with sentry_sdk.start_transaction(op="task", name="Test Transactions"): + placeholder_fn() - with sentry_sdk.start_transaction(op="task", name="Test Transactions"): - placeholder_fn() poll_for_response( f"{SENTRY_TEST_HOST}/api/0/organizations/sentry/events/?dataset=profiles&field=profile.id&project=1&statsPeriod=1h", client, From ed04842604c396e8e11d32a375208c20ec87554b Mon Sep 17 00:00:00 2001 From: anthony sottile <103459774+asottile-sentry@users.noreply.github.com> Date: Tue, 3 Jun 2025 16:56:16 -0400 Subject: [PATCH 167/305] remove index workaround (#3730) a hard stop is in place with this so it can be removed now --- install/set-up-and-migrate-database.sh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/install/set-up-and-migrate-database.sh b/install/set-up-and-migrate-database.sh index 2d4e13208e3..50822a47b75 100644 --- a/install/set-up-and-migrate-database.sh +++ b/install/set-up-and-migrate-database.sh @@ -10,15 +10,6 @@ if [[ -z "${SKIP_SENTRY_MIGRATIONS:-}" ]]; then exit 1 fi - # Using django ORM to provide broader support for users with external databases - $dcr web shell -c " -from django.db import connection - -with connection.cursor() as cursor: - cursor.execute('ALTER TABLE IF EXISTS sentry_groupedmessage DROP CONSTRAINT IF EXISTS sentry_groupedmessage_project_id_id_515aaa7e_uniq;') - cursor.execute('DROP INDEX IF EXISTS sentry_groupedmessage_project_id_id_515aaa7e_uniq;') -" - if [[ -n "${CI:-}" || "${SKIP_USER_CREATION:-0}" == 1 ]]; then $dcr web upgrade --noinput --create-kafka-topics echo "" From e684c7e3bd09e0a697442330a8600d6845528b96 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 4 Jun 2025 12:44:58 +0700 Subject: [PATCH 168/305] chore: prune removed feature flags on main repository (#3731) --- sentry/sentry.conf.example.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 902c393fcf2..2b10e77300d 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -294,20 +294,11 @@ def get_internal_network(): ) # Starfish related flags + ( - "organizations:deprecate-fid-from-performance-score", "organizations:indexed-spans-extraction", "organizations:insights-entry-points", "organizations:insights-initial-modules", "organizations:insights-addon-modules", - "organizations:mobile-ttid-ttfd-contribution", - "organizations:performance-calculate-score-relay", "organizations:standalone-span-ingestion", - "organizations:starfish-browser-resource-module-image-view", - "organizations:starfish-browser-resource-module-ui", - "organizations:starfish-browser-webvitals", - "organizations:starfish-browser-webvitals-pageoverview-v2", - "organizations:starfish-browser-webvitals-replace-fid-with-inp", - "organizations:starfish-browser-webvitals-use-backend-scores", "organizations:starfish-mobile-appstart", "projects:span-metrics-extraction", "projects:span-metrics-extraction-addons", From 1217f469ec4a7d1f8329494f7b61927f5156c28a Mon Sep 17 00:00:00 2001 From: Pierre Massat Date: Fri, 6 Jun 2025 17:07:49 -0700 Subject: [PATCH 169/305] fix(profiles): Run the profile chunks consumer (#3739) --- docker-compose.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 75a86e2e59b..ae520f7135e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -299,6 +299,11 @@ services: command: rust-consumer --storage functions_raw --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset profiles: - feature-complete + snuba-profiling-profile-chunks-consumer: + <<: *snuba_defaults + command: rust-consumer --storage profile_chunks --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + profiles: + - feature-complete snuba-spans-consumer: <<: *snuba_defaults command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset From c8ee02de19c71dd89f722060f6a7d90d0c619378 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Wed, 11 Jun 2025 10:57:24 -0400 Subject: [PATCH 170/305] feat: Add taskbroker + worker + scheduler (#3738) --- .env | 1 + .github/ISSUE_TEMPLATE/release.yml | 1 + docker-compose.yml | 22 ++++++++++++++++++++++ scripts/bump-version.sh | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.env b/.env index 5688114306b..a73d4dd4ba7 100644 --- a/.env +++ b/.env @@ -13,6 +13,7 @@ SENTRY_IMAGE=getsentry/sentry:nightly SNUBA_IMAGE=getsentry/snuba:nightly RELAY_IMAGE=getsentry/relay:nightly SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +TASKBROKER_IMAGE=getsentry/taskbroker:nightly VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/.github/ISSUE_TEMPLATE/release.yml b/.github/ISSUE_TEMPLATE/release.yml index 48691f3255d..545e733befe 100644 --- a/.github/ISSUE_TEMPLATE/release.yml +++ b/.github/ISSUE_TEMPLATE/release.yml @@ -15,6 +15,7 @@ body: - [ ] [`snuba`](https://github.com/getsentry/snuba/actions/workflows/release.yml) - [ ] [`symbolicator`](https://github.com/getsentry/symbolicator/actions/workflows/release.yml) - [ ] [`vroom`](https://github.com/getsentry/vroom/actions/workflows/release.yaml) + - [ ] [`taskbroker`](https://github.com/getsentry/taskbroker/actions/workflows/release.yml) - [ ] Release self-hosted. - [ ] [Prepare the `self-hosted` release](https://github.com/getsentry/self-hosted/actions/workflows/release.yml) (_replace with publish issue repo link_). - [ ] Check to make sure the new release branch in self-hosted includes the appropriate CalVer images. diff --git a/docker-compose.yml b/docker-compose.yml index ae520f7135e..b1805dd3a09 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -487,6 +487,24 @@ services: <<: *depends_on-healthy web: <<: *depends_on-healthy + taskbroker: + <<: *restart_policy + image: "$TASKBROKER_IMAGE" + environment: + TASKBROKER_KAFKA_CLUSTER: "kafka:9092" + TASKBROKER_KAFKA_DEADLETTER_CLUSTER: "kafka:9092" + TASKBROKER_DB_PATH: "/opt/sqlite/taskbroker-activations.sqlite" + volumes: + - sentry-taskbroker:/opt/sqlite + depends_on: + kafka: + <<: *depends_on-healthy + taskscheduler: + <<: *sentry_defaults + command: run taskworker-scheduler + taskworker: + <<: *sentry_defaults + command: run taskworker --concurrency=4 --rpc-host=taskbroker:50051 --num-brokers=1 vroom: <<: *restart_policy image: "$VROOM_IMAGE" @@ -541,6 +559,10 @@ volumes: # Not being external will still persist data across restarts. # It won't persist if someone does a docker compose down -v. sentry-vroom: + # This volume stores task data that is inflight + # It should persist across restarts. If this volume is + # deleted, up to ~2048 tasks will be lost. + sentry-taskbroker: # These store ephemeral data that needn't persist across restarts. # That said, volumes will be persisted across restarts until they are deleted. sentry-secrets: diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index 808df09aa17..5e53ec81b20 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -4,7 +4,7 @@ set -eu OLD_VERSION="$1" NEW_VERSION="$2" -sed -i -e "s/^\(SENTRY\|SNUBA\|RELAY\|SYMBOLICATOR\|VROOM\)_IMAGE=\([^:]\+\):.\+\$/\1_IMAGE=\2:$NEW_VERSION/" .env +sed -i -e "s/^\(SENTRY\|SNUBA\|RELAY\|SYMBOLICATOR\|TASKBROKER\|VROOM\)_IMAGE=\([^:]\+\):.\+\$/\1_IMAGE=\2:$NEW_VERSION/" .env sed -i -e "s/^\# Self-Hosted Sentry .*/# Self-Hosted Sentry $NEW_VERSION/" README.md echo "New version: $NEW_VERSION" From 4c973e0824d5eb5352d9dfd21789227fcc5da748 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 12 Jun 2025 07:55:54 +0700 Subject: [PATCH 171/305] feat(features): enable continuous profiling (#3742) --- sentry/sentry.conf.example.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 2b10e77300d..79c7aefa6cd 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -309,6 +309,11 @@ def get_internal_network(): "organizations:user-feedback-replay-clip", "organizations:user-feedback-ui", ) + # Continuous Profiling related flags + + ( + "organizations:continuous-profiling", + "organizations:continuous-profiling-stats", + ) } ) From 2f2bb9c925c780dc456198adc288f8a1aa8a94f7 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Fri, 13 Jun 2025 10:43:39 +0200 Subject: [PATCH 172/305] tests: Install version 2.x of Python SDK (#3745) --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 62b4166f202..97d735ef800 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,4 @@ -sentry-sdk>=2.4.0 +sentry-sdk>=2.4.0,<3.0.0 pytest>=8.0.0 pytest-cov>=4.1.0 pytest-rerunfailures>=11.0 From 0730d8c8c7ee653b88307f860356fa827f0e9fae Mon Sep 17 00:00:00 2001 From: Nikita Korolev <66738864+doc-sheet@users.noreply.github.com> Date: Fri, 13 Jun 2025 11:52:47 +0300 Subject: [PATCH 173/305] add shellcheck action to lint bash scripts (#3710) * add shellcheck action to lint bash scripts * fix some shellcheck warnings --------- Co-authored-by: ds Co-authored-by: Burak Yigit Kaya --- .github/workflows/shellcheck.yml | 40 ++++++++++++++++++++++++++++++++ install/_lib.sh | 9 +++---- 2 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/shellcheck.yml diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml new file mode 100644 index 00000000000..e2d06d1ae53 --- /dev/null +++ b/.github/workflows/shellcheck.yml @@ -0,0 +1,40 @@ +--- +name: "ShellCheck" +on: + push: + paths: + - "**.sh" + branches: [master] + pull_request: + paths: + - "**.sh" + branches: [master] + +jobs: + shellcheck: + name: ShellCheck + runs-on: ubuntu-latest + steps: + - name: Repository checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run ShellCheck + run: | + git diff --name-only -z `git merge-base origin/master HEAD` -- \ + 'install/_lib.sh' \ + | xargs -0 -r -- \ + shellcheck \ + --shell=bash \ + --exclude=SC1090,SC1091 \ + --format=json1 \ + | jq -r ' + .comments + | map(.level |= if ([.] | inside(["info", "style"])) then "notice" else . end) + | .[] as $note + | "::\($note.level) file=\($note.file),line=\($note.line),endLine=\($note.endLine),col=\($note.column),endColumn=\($note.endColumn)::[SC\($note.code)] \($note.message)" + ' \ + | grep . >&2 && exit 1 + + exit 0 diff --git a/install/_lib.sh b/install/_lib.sh index 9abbf1a3d3b..3beb18e38db 100644 --- a/install/_lib.sh +++ b/install/_lib.sh @@ -33,6 +33,7 @@ function ensure_file_from_example { echo "$target already exists, skipped creation." else # sed from https://stackoverflow.com/a/25123013/90297 + # shellcheck disable=SC2001 example="$(echo "$target" | sed 's/\.[^.]*$/.example&/')" if [[ ! -f "$example" ]]; then echo "Oops! Where did $example go? 🤨 We need it in order to create $target." @@ -45,14 +46,14 @@ function ensure_file_from_example { # Check the version of $1 is greater than or equal to $2 using sort. Note: versions must be stripped of "v" function vergte() { - printf "%s\n%s" $1 $2 | sort --version-sort --check=quiet --reverse + printf "%s\n%s" "$1" "$2" | sort --version-sort --check=quiet --reverse } -SENTRY_CONFIG_PY=sentry/sentry.conf.py -SENTRY_CONFIG_YML=sentry/config.yml +export SENTRY_CONFIG_PY=sentry/sentry.conf.py +export SENTRY_CONFIG_YML=sentry/config.yml # Increase the default 10 second SIGTERM timeout # to ensure celery queues are properly drained # between upgrades as task signatures may change across # versions -STOP_TIMEOUT=60 # seconds +export STOP_TIMEOUT=60 # seconds From 1b88e90e30f1c920aa274e834c59a6d073028cec Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 13 Jun 2025 15:55:30 +0700 Subject: [PATCH 174/305] Introduce patches with external kafka (#3521) * Introduce patches with external kafka * Fix pre-commit hooks * Patch relay config file * Documentation for patches stuff * Provide more helpful information for Docker Compose Override file * Fix grep command * ref: rename to 'optional-modifications' * chore(pre-commit): exclude .patch extension * chore(pre-commit): escape backslash * chore(pre-commit): put exclude field on hooks * chore(pre-commit): put exclude field on top level Based on https://pre-commit.com/#top_level-exclude * chore(pre-commit): move to even more top level --- .pre-commit-config.yaml | 2 +- optional-modifications/README.md | 41 +++++ optional-modifications/_lib.sh | 15 ++ .../patches/external-kafka/.env.patch | 22 +++ .../external-kafka/config.example.yml.patch | 19 +++ .../external-kafka/docker-compose.yml.patch | 142 ++++++++++++++++++ .../sentry.conf.example.py.patch | 21 +++ 7 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 optional-modifications/README.md create mode 100755 optional-modifications/_lib.sh create mode 100644 optional-modifications/patches/external-kafka/.env.patch create mode 100644 optional-modifications/patches/external-kafka/config.example.yml.patch create mode 100644 optional-modifications/patches/external-kafka/docker-compose.yml.patch create mode 100644 optional-modifications/patches/external-kafka/sentry.conf.example.py.patch diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1d995372865..9d544410bab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,4 @@ +exclude: '\.patch$' repos: - repo: local hooks: @@ -11,7 +12,6 @@ repos: args: [-w, -d] files: .*\.sh stages: [commit, merge-commit, push, manual] - - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 hooks: diff --git a/optional-modifications/README.md b/optional-modifications/README.md new file mode 100644 index 00000000000..84cf7e0e2b9 --- /dev/null +++ b/optional-modifications/README.md @@ -0,0 +1,41 @@ +# Optional Modifications + +Other than the default self-hosted Sentry installation, sometimes users +can leverage their existing infrastructure to help them with limited +resources. "Patches", or you might call this like a "plugin system", is +a collection of patch files (see [man patch(1)](https://man7.org/linux/man-pages/man1/patch.1.html)) +that can be used with to modify the existing configuration to achieve +the desired goal. + +> [!WARNING] +> Beware that this is very experimental and might not work as expected. +> +> **Use it at your own risk!** + +## How to use patches + +The patches are designed mostly to help modify the existing +configuration files. You will need to run the `install.sh` script +afterwards. + +They should be run from the root directory. For example, the +`external-kafka` patches should be run as: + +```bash +patch < optional-modifications/patches/external-kafka/.env.patch +patch < optional-modifications/patches/external-kafka/config.example.yml.patch +patch < optional-modifications/patches/external-kafka/sentry.conf.example.py.patch +patch < optional-modifications/patches/external-kafka/docker-compose.yml.patch +``` + +Some patches might require additional steps to be taken, like providing +credentials or additional TLS certificates. + +## Official support + +Sentry employees are not obliged to provide dedicated support for +patches, but they can help by providing information to move us forward. +We encourage the community to contribute for any bug fixes or +improvements. + +See the [support policy for self-hosted Sentry](https://develop.sentry.dev/self-hosted/support/) for more information. diff --git a/optional-modifications/_lib.sh b/optional-modifications/_lib.sh new file mode 100755 index 00000000000..46e55d3e257 --- /dev/null +++ b/optional-modifications/_lib.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -euo pipefail +test "${DEBUG:-}" && set -x + +function patch_file() { + target="$1" + content="$2" + if [[ -f "$target" ]]; then + echo "🙈 Patching $target ..." + patch -p1 <"$content" + else + echo "🙊 Skipping $target ..." + fi +} diff --git a/optional-modifications/patches/external-kafka/.env.patch b/optional-modifications/patches/external-kafka/.env.patch new file mode 100644 index 00000000000..36e45f7785f --- /dev/null +++ b/optional-modifications/patches/external-kafka/.env.patch @@ -0,0 +1,22 @@ +--- .env 2025-02-04 07:31:54.868049984 +0700 ++++ .env.external-kafka 2025-05-15 08:33:15.442361105 +0700 +@@ -22,3 +22,19 @@ + POSTGRES_MAX_CONNECTIONS=100 + # Set SETUP_JS_SDK_ASSETS to 1 to enable the setup of JS SDK assets + # SETUP_JS_SDK_ASSETS=1 ++ ++################################################################################ ++## Additional External Kafka options ++################################################################################ ++KAFKA_BOOTSTRAP_SERVERS=kafka-node1:9092,kafka-node2:9092,kafka-node3:9092 ++# Valid options are PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL ++KAFKA_SECURITY_PROTOCOL=PLAINTEXT ++# Valid options are PLAIN, SCRAM-SHA-256, SCRAM-SHA-512. Other mechanism might be unavailable. ++# KAFKA_SASL_MECHANISM=PLAIN ++# KAFKA_SASL_USERNAME=username ++# KAFKA_SASL_PASSWORD=password ++# Put your certificates on the \`certificates/kafka\` directory. ++# The certificates will be mounted as read-only volumes. ++# KAFKA_SSL_CA_LOCATION=/kafka-certificates/ca.pem ++# KAFKA_SSL_CERTIFICATE_LOCATION=/kafka-certificates/client.pem ++# KAFKA_SSL_KEY_LOCATION=/kafka-certificates/client.key diff --git a/optional-modifications/patches/external-kafka/config.example.yml.patch b/optional-modifications/patches/external-kafka/config.example.yml.patch new file mode 100644 index 00000000000..a0c1aab04b8 --- /dev/null +++ b/optional-modifications/patches/external-kafka/config.example.yml.patch @@ -0,0 +1,19 @@ +--- relay/config.example.yml 2025-05-15 08:27:40.426876887 +0700 ++++ relay/config.example.external-kafka.yml 2025-05-15 08:34:21.113311217 +0700 +@@ -7,8 +7,15 @@ + processing: + enabled: true + kafka_config: +- - {name: "bootstrap.servers", value: "kafka:9092"} ++ - {name: "bootstrap.servers", value: "kafka-node1:9092,kafka-node2:9092,kafka-node3:9092"} + - {name: "message.max.bytes", value: 50000000} # 50MB ++ - {name: "security.protocol", value: "PLAINTEXT"} ++ - {name: "sasl.mechanism", value: "PLAIN"} # Remove or comment this line if SASL is not used. ++ - {name: "sasl.username", value: "username"} # Remove or comment this line if SASL is not used. ++ - {name: "sasl.password", value: "password"} # Remove or comment this line if SASL is not used. ++ - {name: "ssl.ca.location", value: "/kafka-certificates/ca.pem"} # Remove or comment this line if SSL is not used. ++ - {name: "ssl.certificate.location", value: "/kafka-certificates/client.pem"} # Remove or comment this line if SSL is not used. ++ - {name: "ssl.key.location", value: "/kafka-certificates/client.key"} # Remove or comment this line if SSL is not used. + redis: redis://redis:6379 + geoip_path: "/geoip/GeoLite2-City.mmdb" + diff --git a/optional-modifications/patches/external-kafka/docker-compose.yml.patch b/optional-modifications/patches/external-kafka/docker-compose.yml.patch new file mode 100644 index 00000000000..ad0328410b7 --- /dev/null +++ b/optional-modifications/patches/external-kafka/docker-compose.yml.patch @@ -0,0 +1,142 @@ +--- docker-compose.yml 2025-03-17 13:32:15.120328412 +0700 ++++ docker-compose.external-kafka.yml 2025-05-15 08:39:05.509951068 +0700 +@@ -26,8 +26,6 @@ + depends_on: + redis: + <<: *depends_on-healthy +- kafka: +- <<: *depends_on-healthy + postgres: + <<: *depends_on-healthy + memcached: +@@ -59,6 +57,14 @@ + SENTRY_EVENT_RETENTION_DAYS: + SENTRY_MAIL_HOST: + SENTRY_MAX_EXTERNAL_SOURCEMAP_SIZE: ++ KAFKA_BOOTSTRAP_SERVERS: ${KAFKA_BOOTSTRAP_SERVERS:-kafka:9092} ++ KAFKA_SECURITY_PROTOCOL: ${KAFKA_SECURITY_PROTOCOL:-PLAINTEXT} ++ KAFKA_SSL_CA_LOCATION: ${KAFKA_SSL_CA_LOCATION:-} ++ KAFKA_SSL_CERTIFICATE_LOCATION: ${KAFKA_SSL_CERTIFICATE_LOCATION:-} ++ KAFKA_SSL_KEY_LOCATION: ${KAFKA_SSL_KEY_LOCATION:-} ++ KAFKA_SASL_MECHANISM: ${KAFKA_SASL_MECHANISM:-} ++ KAFKA_SASL_USERNAME: ${KAFKA_SASL_USERNAME:-} ++ KAFKA_SASL_PASSWORD: ${KAFKA_SASL_PASSWORD:-} + volumes: + - "sentry-data:/data" + - "./sentry:/etc/sentry" +@@ -69,15 +75,20 @@ + depends_on: + clickhouse: + <<: *depends_on-healthy +- kafka: +- <<: *depends_on-healthy + redis: + <<: *depends_on-healthy + image: "$SNUBA_IMAGE" + environment: + SNUBA_SETTINGS: self_hosted + CLICKHOUSE_HOST: clickhouse +- DEFAULT_BROKERS: "kafka:9092" ++ DEFAULT_BROKERS: ${KAFKA_BOOTSTRAP_SERVERS:-kafka:9092} ++ KAFKA_SECURITY_PROTOCOL: ${KAFKA_SECURITY_PROTOCOL:-PLAINTEXT} ++ KAFKA_SSL_CA_PATH: ${KAFKA_SSL_CA_LOCATION:-} ++ KAFKA_SSL_CERT_PATH: ${KAFKA_SSL_CERTIFICATE_LOCATION:-} ++ KAFKA_SSL_KEY_PATH: ${KAFKA_SSL_KEY_LOCATION:-} ++ KAFKA_SASL_MECHANISM: ${KAFKA_SASL_MECHANISM:-} ++ KAFKA_SASL_USERNAME: ${KAFKA_SASL_USERNAME:-} ++ KAFKA_SASL_PASSWORD: ${KAFKA_SASL_PASSWORD:-} + REDIS_HOST: redis + UWSGI_MAX_REQUESTS: "10000" + UWSGI_DISABLE_LOGGING: "true" +@@ -140,43 +151,7 @@ + POSTGRES_HOST_AUTH_METHOD: "trust" + volumes: + - "sentry-postgres:/var/lib/postgresql/data" +- kafka: +- <<: *restart_policy +- image: "confluentinc/cp-kafka:7.6.1" +- environment: +- # https://docs.confluent.io/platform/current/installation/docker/config-reference.html#cp-kakfa-example +- KAFKA_PROCESS_ROLES: "broker,controller" +- KAFKA_CONTROLLER_QUORUM_VOTERS: "1001@127.0.0.1:29093" +- KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER" +- KAFKA_NODE_ID: "1001" +- CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk" +- KAFKA_LISTENERS: "PLAINTEXT://0.0.0.0:29092,INTERNAL://0.0.0.0:9093,EXTERNAL://0.0.0.0:9092,CONTROLLER://0.0.0.0:29093" +- KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://127.0.0.1:29092,INTERNAL://kafka:9093,EXTERNAL://kafka:9092" +- KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "PLAINTEXT:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT" +- KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT" +- KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1" +- KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS: "1" +- KAFKA_LOG_RETENTION_HOURS: "24" +- KAFKA_MESSAGE_MAX_BYTES: "50000000" #50MB or bust +- KAFKA_MAX_REQUEST_SIZE: "50000000" #50MB on requests apparently too +- CONFLUENT_SUPPORT_METRICS_ENABLE: "false" +- KAFKA_LOG4J_LOGGERS: "kafka.cluster=WARN,kafka.controller=WARN,kafka.coordinator=WARN,kafka.log=WARN,kafka.server=WARN,state.change.logger=WARN" +- KAFKA_LOG4J_ROOT_LOGLEVEL: "WARN" +- KAFKA_TOOLS_LOG4J_LOGLEVEL: "WARN" +- ulimits: +- nofile: +- soft: 4096 +- hard: 4096 +- volumes: +- - "sentry-kafka:/var/lib/kafka/data" +- - "sentry-kafka-log:/var/lib/kafka/log" +- - "sentry-secrets:/etc/kafka/secrets" +- healthcheck: +- <<: *healthcheck_defaults +- test: ["CMD-SHELL", "nc -z localhost 9092"] +- interval: 10s +- timeout: 10s +- retries: 30 ++ kafka: !reset null + clickhouse: + <<: *restart_policy + image: clickhouse-self-hosted-local +@@ -475,9 +450,8 @@ + read_only: true + source: ./geoip + target: /geoip ++ - ./certificates/kafka:/kafka-certificates:ro + depends_on: +- kafka: +- <<: *depends_on-healthy + redis: + <<: *depends_on-healthy + web: +@@ -486,15 +460,21 @@ + <<: *restart_policy + image: "$VROOM_IMAGE" + environment: +- SENTRY_KAFKA_BROKERS_PROFILING: "kafka:9092" +- SENTRY_KAFKA_BROKERS_OCCURRENCES: "kafka:9092" ++ SENTRY_KAFKA_BROKERS_PROFILING: ${KAFKA_BOOTSTRAP_SERVERS:-kafka:9092} ++ SENTRY_KAFKA_BROKERS_OCCURRENCES: ${KAFKA_BOOTSTRAP_SERVERS:-kafka:9092} ++ SENTRY_KAFKA_BROKERS_SPANS: ${KAFKA_BOOTSTRAP_SERVERS:-kafka:9092} ++ SENTRY_KAFKA_SECURITY_PROTOCOL: ${KAFKA_SECURITY_PROTOCOL:-PLAINTEXT} ++ SENTRY_KAFKA_SSL_CA_PATH: ${KAFKA_SSL_CA_LOCATION:-} ++ SENTRY_KAFKA_SSL_CERT_PATH: ${KAFKA_SSL_CERTIFICATE_LOCATION:-} ++ SENTRY_KAFKA_SSL_KEY_PATH: ${KAFKA_SSL_KEY_LOCATION:-} ++ SENTRY_KAFKA_SASL_MECHANISM: ${KAFKA_SASL_MECHANISM:-} ++ SENTRY_KAFKA_SASL_USERNAME: ${KAFKA_SASL_USERNAME:-} ++ SENTRY_KAFKA_SASL_PASSWORD: ${KAFKA_SASL_PASSWORD:-} + SENTRY_BUCKET_PROFILES: file://localhost//var/lib/sentry-profiles + SENTRY_SNUBA_HOST: "http://snuba-api:1218" + volumes: + - sentry-vroom:/var/lib/sentry-profiles +- depends_on: +- kafka: +- <<: *depends_on-healthy ++ - ./certificates/kafka:/kafka-certificates:ro + profiles: + - feature-complete + vroom-cleanup: +@@ -523,8 +503,6 @@ + external: true + sentry-redis: + external: true +- sentry-kafka: +- external: true + sentry-clickhouse: + external: true + sentry-symbolicator: diff --git a/optional-modifications/patches/external-kafka/sentry.conf.example.py.patch b/optional-modifications/patches/external-kafka/sentry.conf.example.py.patch new file mode 100644 index 00000000000..abc755c00a0 --- /dev/null +++ b/optional-modifications/patches/external-kafka/sentry.conf.example.py.patch @@ -0,0 +1,21 @@ +--- sentry/sentry.conf.example.py 2025-05-15 08:27:40.427876868 +0700 ++++ sentry/sentry.conf.example.external-kafka.py 2025-05-15 08:32:44.845127931 +0700 +@@ -132,9 +132,17 @@ + SENTRY_CACHE = "sentry.cache.redis.RedisCache" + + DEFAULT_KAFKA_OPTIONS = { +- "bootstrap.servers": "kafka:9092", ++ "bootstrap.servers": env("KAFKA_BOOTSTRAP_SERVERS", "kafka:9092"), + "message.max.bytes": 50000000, + "socket.timeout.ms": 1000, ++ "security.protocol": env("KAFKA_SECURITY_PROTOCOL", "PLAINTEXT"), # Valid options are PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL ++ # If you don't use any of these options below, you can remove them or set them to `None`. ++ "sasl.mechanism": env("KAFKA_SASL_MECHANISM", None), # Valid options are PLAIN, SCRAM-SHA-256, SCRAM-SHA-512. Other mechanism might be unavailable. ++ "sasl.username": env("KAFKA_SASL_USERNAME", None), ++ "sasl.password": env("KAFKA_SASL_PASSWORD", None), ++ "ssl.ca.location": env("KAFKA_SSL_CA_LOCATION", None), # Remove this line if SSL is not used. ++ "ssl.certificate.location": env("KAFKA_SSL_CERTIFICATE_LOCATION", None), # Remove this line if SSL is not used. ++ "ssl.key.location": env("KAFKA_SSL_KEY_LOCATION", None), # Remove this line if SSL is not used. + } + + SENTRY_EVENTSTREAM = "sentry.eventstream.kafka.KafkaEventStream" From 2b6bd5f9e86cce1ef36b45ab23a4eaf0b1ccd119 Mon Sep 17 00:00:00 2001 From: Vita Chumakova Date: Sat, 14 Jun 2025 03:49:46 +0400 Subject: [PATCH 175/305] feat: migrate to arm64-compatible smtp image (#3746) --- docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b1805dd3a09..600e757cd12 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -91,12 +91,12 @@ x-snuba-defaults: &snuba_defaults services: smtp: <<: *restart_policy - platform: linux/amd64 - image: tianon/exim4 - hostname: "${SENTRY_MAIL_HOST:-}" + image: registry.gitlab.com/egos-tech/smtp volumes: - "sentry-smtp:/var/spool/exim4" - "sentry-smtp-log:/var/log/exim4" + environment: + - MAILNAME=${SENTRY_MAIL_HOST:-} memcached: <<: *restart_policy image: "memcached:1.6.26-alpine" From 66c057b4e2281ec009811023fad33ebcc9131be0 Mon Sep 17 00:00:00 2001 From: Nikita Korolev <66738864+doc-sheet@users.noreply.github.com> Date: Sat, 14 Jun 2025 02:50:26 +0300 Subject: [PATCH 176/305] enable shell linter for more scripts (#3748) --- .github/workflows/shellcheck.yml | 8 +++++-- scripts/_lib.sh | 32 +++++++++++++++---------- scripts/bump-version.sh | 1 + scripts/restore.sh | 1 + unit-test.sh | 2 +- workstation/200_download-self-hosted.sh | 2 +- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index e2d06d1ae53..c5cc25e8cbb 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -23,12 +23,16 @@ jobs: - name: Run ShellCheck run: | git diff --name-only -z `git merge-base origin/master HEAD` -- \ - 'install/_lib.sh' \ + install/_lib.sh \ + 'optional-modifications/**.sh' \ + 'scripts/**.sh' \ + unit-test.sh \ + 'workstation/**.sh' \ | xargs -0 -r -- \ shellcheck \ --shell=bash \ - --exclude=SC1090,SC1091 \ --format=json1 \ + --external-sources \ | jq -r ' .comments | map(.level |= if ([.] | inside(["info", "style"])) then "notice" else . end) diff --git a/scripts/_lib.sh b/scripts/_lib.sh index a742f8acc51..ba57fc42a33 100755 --- a/scripts/_lib.sh +++ b/scripts/_lib.sh @@ -7,7 +7,7 @@ if [ -n "${DEBUG:-}" ]; then fi function confirm() { - read -p "$1 [y/n] " confirmation + read -r -p "$1 [y/n] " confirmation if [ "$confirmation" != "y" ]; then echo "Canceled. 😅" exit @@ -26,8 +26,7 @@ function reset() { # we're targeting a valid tag here. Do this early in order to fail fast. if [ -n "$version" ]; then set +e - git rev-parse --verify --quiet "refs/tags/$version" >/dev/null - if [ $? -gt 0 ]; then + if ! git rev-parse --verify --quiet "refs/tags/$version" >/dev/null; then echo "Bad version: $version" exit fi @@ -43,12 +42,15 @@ function reset() { echo "Okay ... good luck! 😰" fi + # assert that commands are defined + : "${dc:?}" "${cmd:?}" + # Hit the reset button. $dc down --volumes --remove-orphans --rmi local # Remove any remaining (likely external) volumes with name matching 'sentry-.*'. for volume in $(docker volume list --format '{{ .Name }}' | grep '^sentry-'); do - docker volume remove $volume >/dev/null && + docker volume remove "$volume" >/dev/null && echo "Removed volume: $volume" || echo "Skipped volume: $volume" done @@ -60,30 +62,34 @@ function reset() { } function backup() { + local type + type=${1:-"global"} - touch $(pwd)/sentry/backup.json - chmod 666 $(pwd)/sentry/backup.json - $dc run -v $(pwd)/sentry:/sentry-data/backup --rm -T -e SENTRY_LOG_LEVEL=CRITICAL web export $type /sentry-data/backup/backup.json + touch "${PWD}/sentry/backup.json" + chmod 666 "${PWD}/sentry/backup.json" + $dc run -v "${PWD}/sentry:/sentry-data/backup" --rm -T -e SENTRY_LOG_LEVEL=CRITICAL web export "$type" /sentry-data/backup/backup.json } function restore() { - type=${1:-"global"} - $dc run --rm -T web import $type /etc/sentry/backup.json + local type + + type="${1:-global}" + $dc run --rm -T web import "$type" /etc/sentry/backup.json } # Needed variables to source error-handling script MINIMIZE_DOWNTIME="${MINIMIZE_DOWNTIME:-}" -STOP_TIMEOUT=60 +export STOP_TIMEOUT=60 # Save logs in order to send envelope to Sentry -log_file=sentry_"${cmd%% *}"_log-$(date +'%Y-%m-%d_%H-%M-%S').txt +log_file="sentry_${cmd%% *}_log-$(date +%Y-%m-%d_%H-%M-%S).txt" exec &> >(tee -a "$log_file") version="" while (($#)); do case "$1" in - --report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=1 ;; - --no-report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=0 ;; + --report-self-hosted-issues) export REPORT_SELF_HOSTED_ISSUES=1 ;; + --no-report-self-hosted-issues) export REPORT_SELF_HOSTED_ISSUES=0 ;; *) version=$1 ;; esac shift diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index 5e53ec81b20..f5853a3e2f4 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -7,4 +7,5 @@ NEW_VERSION="$2" sed -i -e "s/^\(SENTRY\|SNUBA\|RELAY\|SYMBOLICATOR\|TASKBROKER\|VROOM\)_IMAGE=\([^:]\+\):.\+\$/\1_IMAGE=\2:$NEW_VERSION/" .env sed -i -e "s/^\# Self-Hosted Sentry .*/# Self-Hosted Sentry $NEW_VERSION/" README.md +[ -z "$OLD_VERSION" ] || echo "Previous version: $OLD_VERSION" echo "New version: $NEW_VERSION" diff --git a/scripts/restore.sh b/scripts/restore.sh index ededd3114f3..ae3666b0ec6 100755 --- a/scripts/restore.sh +++ b/scripts/restore.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash cmd="restore $1" source scripts/_lib.sh + $cmd diff --git a/unit-test.sh b/unit-test.sh index 01a945e3777..8dbc0d727bd 100755 --- a/unit-test.sh +++ b/unit-test.sh @@ -5,7 +5,7 @@ export REPORT_SELF_HOSTED_ISSUES=0 # will be over-ridden in the relevant test FORCE_CLEAN=1 "./scripts/reset.sh" fail=0 for test_file in _unit-test/*-test.sh; do - if [ "$1" -a "$1" != "$test_file" ]; then + if [ -n "$1" ] && [ "$1" != "$test_file" ]; then echo "🙊 Skipping $test_file ..." continue fi diff --git a/workstation/200_download-self-hosted.sh b/workstation/200_download-self-hosted.sh index a07735d7003..406a52c184d 100644 --- a/workstation/200_download-self-hosted.sh +++ b/workstation/200_download-self-hosted.sh @@ -1,5 +1,5 @@ #!/bin/bash -# +set -eo pipefail # Create getsentry folder and enter. mkdir /home/user/getsentry From 45c21c42bbbc3067aa3d5edeb2f0d0e747fa0f9d Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sun, 15 Jun 2025 18:06:17 +0000 Subject: [PATCH 177/305] release: 25.6.0 --- .env | 12 ++++++------ CHANGELOG.md | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.env b/.env index a73d4dd4ba7..2a80e2b330e 100644 --- a/.env +++ b/.env @@ -9,12 +9,12 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -TASKBROKER_IMAGE=getsentry/taskbroker:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.6.0 +SNUBA_IMAGE=getsentry/snuba:25.6.0 +RELAY_IMAGE=getsentry/relay:25.6.0 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.6.0 +TASKBROKER_IMAGE=getsentry/taskbroker:25.6.0 +VROOM_IMAGE=getsentry/vroom:25.6.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index d421410f31c..1460ee3a644 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 25.6.0 + +### Various fixes & improvements + +- enable shell linter for more scripts (#3748) by @doc-sheet +- feat: migrate to arm64-compatible smtp image (#3746) by @ezhevita +- Introduce patches with external kafka (#3521) by @aldy505 +- add shellcheck action to lint bash scripts (#3710) by @doc-sheet +- tests: Install version 2.x of Python SDK (#3745) by @sentrivana +- feat(features): enable continuous profiling (#3742) by @aldy505 +- feat: Add taskbroker + worker + scheduler (#3738) by @markstory +- fix(profiles): Run the profile chunks consumer (#3739) by @phacops +- chore: prune removed feature flags on main repository (#3731) by @aldy505 +- remove index workaround (#3730) by @asottile-sentry +- Make usage of Python SDK future proof (#3714) by @antonpirker + ## 25.5.1 ### Various fixes & improvements From e07445d6be41793165316a3e077ebec343740530 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 17 Jun 2025 14:00:04 +0100 Subject: [PATCH 178/305] fix(vroom): Explicitly set PROFILES_DIR for upcoming change (#3759) PROFILES_DIR was defaulting to `/var/lib/sentry-profiles` which requires root access. When Vroom image decided to go with non-root default user, this started causing permission issues. Now the image is being refactored and it will not use `/var/lib/sentry-profiles` as the default path so we need to explicitly pass it. --- .env | 2 +- docker-compose.yml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.env b/.env index a73d4dd4ba7..fbb036f177a 100644 --- a/.env +++ b/.env @@ -14,7 +14,7 @@ SNUBA_IMAGE=getsentry/snuba:nightly RELAY_IMAGE=getsentry/relay:nightly SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly TASKBROKER_IMAGE=getsentry/taskbroker:nightly -VROOM_IMAGE=getsentry/vroom:nightly +VROOM_IMAGE=getsentry/vroom:a8e9e04 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/docker-compose.yml b/docker-compose.yml index 600e757cd12..e4e3b77fee7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -511,7 +511,7 @@ services: environment: SENTRY_KAFKA_BROKERS_PROFILING: "kafka:9092" SENTRY_KAFKA_BROKERS_OCCURRENCES: "kafka:9092" - SENTRY_BUCKET_PROFILES: file://localhost//var/lib/sentry-profiles + PROFILES_DIR: "/var/lib/sentry-profiles" SENTRY_SNUBA_HOST: "http://snuba-api:1218" volumes: - sentry-vroom:/var/lib/sentry-profiles @@ -529,10 +529,11 @@ services: BASE_IMAGE: "$VROOM_IMAGE" entrypoint: "/entrypoint.sh" environment: + PROFILES_DIR: "/var/lib/sentry-profiles" # Leaving the value empty to just pass whatever is set # on the host system (or in the .env file) SENTRY_EVENT_RETENTION_DAYS: - command: '"0 0 * * * find /var/lib/sentry-profiles -type f -mtime +$SENTRY_EVENT_RETENTION_DAYS -delete"' + command: '"0 0 * * * find $PROFILES_DIR -type f -mtime +$SENTRY_EVENT_RETENTION_DAYS -delete"' volumes: - sentry-vroom:/var/lib/sentry-profiles profiles: From 019d372df265e7e2cbf32d31d37850203e64bf93 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Tue, 17 Jun 2025 13:26:01 -0700 Subject: [PATCH 179/305] Revert "fix(vroom): Explicitly set PROFILES_DIR for upcoming change" (#3760) * Revert "fix(vroom): Explicitly set PROFILES_DIR for upcoming change (#3759)" This reverts commit e07445d6be41793165316a3e077ebec343740530. It also very importantly changes where we mount the profiles volume which fixes the issue. Our theory is as follows: 1. Vroom Dockerfile had a line doing `mkdirp /var/lib/sentry-profiles` at image build time. This makes the directory owned by `root` 2. When we mount over that directory, and change permissions we can store the permissions changes _in_ the directory but not the directory itself 3. So when we start the vroom image with the new mount, the contents are owned by `vroom` but the main directory is still owned by `root`. This is also why [this approach](https://github.com/getsentry/vroom/pull/601/files/a23a4e395269ca39fd9bd93ecf902cb42530b5cd) worked as the entrypoint script did this at the start of every container instance. --------- Co-authored-by: Burak Yigit Kaya --- .env | 2 +- docker-compose.yml | 15 +++++---------- install.sh | 1 + .../ensure-correct-permissions-profiles-dir.sh | 7 +++++++ .../external-kafka/docker-compose.yml.patch | 4 ++-- 5 files changed, 16 insertions(+), 13 deletions(-) create mode 100755 install/ensure-correct-permissions-profiles-dir.sh diff --git a/.env b/.env index fbb036f177a..a73d4dd4ba7 100644 --- a/.env +++ b/.env @@ -14,7 +14,7 @@ SNUBA_IMAGE=getsentry/snuba:nightly RELAY_IMAGE=getsentry/relay:nightly SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly TASKBROKER_IMAGE=getsentry/taskbroker:nightly -VROOM_IMAGE=getsentry/vroom:a8e9e04 +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/docker-compose.yml b/docker-compose.yml index e4e3b77fee7..70c9327dfe6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -131,11 +131,7 @@ services: # Using default user "postgres" from sentry/sentry.conf.example.py or value of POSTGRES_USER if provided test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"] command: - [ - "postgres", - "-c", - "max_connections=${POSTGRES_MAX_CONNECTIONS:-100}", - ] + ["postgres", "-c", "max_connections=${POSTGRES_MAX_CONNECTIONS:-100}"] environment: POSTGRES_HOST_AUTH_METHOD: "trust" volumes: @@ -511,10 +507,10 @@ services: environment: SENTRY_KAFKA_BROKERS_PROFILING: "kafka:9092" SENTRY_KAFKA_BROKERS_OCCURRENCES: "kafka:9092" - PROFILES_DIR: "/var/lib/sentry-profiles" + SENTRY_BUCKET_PROFILES: file:///var/vroom/sentry-profiles SENTRY_SNUBA_HOST: "http://snuba-api:1218" volumes: - - sentry-vroom:/var/lib/sentry-profiles + - sentry-vroom:/var/vroom/sentry-profiles depends_on: kafka: <<: *depends_on-healthy @@ -529,13 +525,12 @@ services: BASE_IMAGE: "$VROOM_IMAGE" entrypoint: "/entrypoint.sh" environment: - PROFILES_DIR: "/var/lib/sentry-profiles" # Leaving the value empty to just pass whatever is set # on the host system (or in the .env file) SENTRY_EVENT_RETENTION_DAYS: - command: '"0 0 * * * find $PROFILES_DIR -type f -mtime +$SENTRY_EVENT_RETENTION_DAYS -delete"' + command: '"0 0 * * * find /var/vroom/sentry-profiles -type f -mtime +$SENTRY_EVENT_RETENTION_DAYS -delete"' volumes: - - sentry-vroom:/var/lib/sentry-profiles + - sentry-vroom:/var/vroom/sentry-profiles profiles: - feature-complete diff --git a/install.sh b/install.sh index 86e4de1b404..d7f8a036f4e 100755 --- a/install.sh +++ b/install.sh @@ -38,6 +38,7 @@ source install/update-docker-images.sh source install/build-docker-images.sh source install/bootstrap-snuba.sh source install/upgrade-postgres.sh +source install/ensure-correct-permissions-profiles-dir.sh source install/set-up-and-migrate-database.sh source install/geoip.sh source install/setup-js-sdk-assets.sh diff --git a/install/ensure-correct-permissions-profiles-dir.sh b/install/ensure-correct-permissions-profiles-dir.sh new file mode 100755 index 00000000000..68b782bc8a5 --- /dev/null +++ b/install/ensure-correct-permissions-profiles-dir.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# TODO: Remove this after the next hard-stop + +echo "${_group}Ensuring correct permissions on profiles directory ..." +$dcr --no-deps --entrypoint /bin/bash --user root vroom -c 'chown -R vroom:vroom /var/vroom/sentry-profiles && chmod -R o+rwx /var/vroom/sentry-profiles' +echo "${_endgroup}" diff --git a/optional-modifications/patches/external-kafka/docker-compose.yml.patch b/optional-modifications/patches/external-kafka/docker-compose.yml.patch index ad0328410b7..cd669acc784 100644 --- a/optional-modifications/patches/external-kafka/docker-compose.yml.patch +++ b/optional-modifications/patches/external-kafka/docker-compose.yml.patch @@ -120,10 +120,10 @@ + SENTRY_KAFKA_SASL_MECHANISM: ${KAFKA_SASL_MECHANISM:-} + SENTRY_KAFKA_SASL_USERNAME: ${KAFKA_SASL_USERNAME:-} + SENTRY_KAFKA_SASL_PASSWORD: ${KAFKA_SASL_PASSWORD:-} - SENTRY_BUCKET_PROFILES: file://localhost//var/lib/sentry-profiles + SENTRY_BUCKET_PROFILES: file:///var/vroom/sentry-profiles SENTRY_SNUBA_HOST: "http://snuba-api:1218" volumes: - - sentry-vroom:/var/lib/sentry-profiles + - sentry-vroom:/var/vroom/sentry-profiles - depends_on: - kafka: - <<: *depends_on-healthy From 433eed8fb7f80a1dceeebb58691f49cba462e1a0 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 17 Jun 2025 22:47:23 +0100 Subject: [PATCH 180/305] ref(js-assets): Simplify how we call nginx container (#3761) --- _unit-test/js-sdk-assets-test.sh | 6 +++--- install/setup-js-sdk-assets.sh | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/_unit-test/js-sdk-assets-test.sh b/_unit-test/js-sdk-assets-test.sh index 7e2306ecb97..c46c7a51e5f 100755 --- a/_unit-test/js-sdk-assets-test.sh +++ b/_unit-test/js-sdk-assets-test.sh @@ -9,9 +9,9 @@ export SETUP_JS_SDK_ASSETS=1 source install/setup-js-sdk-assets.sh -sdk_files=$($dcr --no-deps -v "sentry-nginx-www:/var/www" nginx ls -lah /var/www/js-sdk/) -sdk_tree=$($dcr --no-deps -v "sentry-nginx-www:/var/www" nginx tree /var/www/js-sdk/ | tail -n 1) -non_empty_file_count=$($dcr --no-deps -v "sentry-nginx-www:/var/www" nginx find /var/www/js-sdk/ -type f -size +1k | wc -l) +sdk_files=$($dcr --no-deps nginx ls -lah /var/www/js-sdk/) +sdk_tree=$($dcr --no-deps nginx tree /var/www/js-sdk/ | tail -n 1) +non_empty_file_count=$($dcr --no-deps nginx find /var/www/js-sdk/ -type f -size +1k | wc -l) # `sdk_files` should contains 5 lines, '4.*', '5.*', '6.*', `7.*` and `8.*` echo $sdk_files diff --git a/install/setup-js-sdk-assets.sh b/install/setup-js-sdk-assets.sh index 51c5e408191..358b67a951a 100644 --- a/install/setup-js-sdk-assets.sh +++ b/install/setup-js-sdk-assets.sh @@ -9,7 +9,7 @@ if [[ "${SETUP_JS_SDK_ASSETS:-}" == "1" ]]; then # `SETUP_JS_SDK_KEEP_OLD_ASSETS` to any value. if [[ -z "${SETUP_JS_SDK_KEEP_OLD_ASSETS:-}" ]]; then echo "Cleaning up old JS SDK assets..." - $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx rm -rf /var/www/js-sdk/* + $dcr --no-deps nginx rm -rf /var/www/js-sdk/* fi $dbuild -t sentry-self-hosted-jq-local --platform="$DOCKER_PLATFORM" jq @@ -35,12 +35,12 @@ if [[ "${SETUP_JS_SDK_ASSETS:-}" == "1" ]]; then variants="{bundle,bundle.tracing,bundle.tracing.replay,bundle.replay,bundle.tracing.replay.feedback,bundle.feedback}" # Download those versions & variants using curl - $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx curl -w '%{response_code} %{url}\n' --no-progress-meter --compressed --retry 3 --create-dirs -fLo "/var/www/js-sdk/#1/#2.min.js" "https://browser.sentry-cdn.com/${versions}/${variants}.min.js" || true + $dcr --no-deps nginx curl -w '%{response_code} %{url}\n' --no-progress-meter --compressed --retry 3 --create-dirs -fLo "/var/www/js-sdk/#1/#2.min.js" "https://browser.sentry-cdn.com/${versions}/${variants}.min.js" || true # Make sure permissions are correct # See https://github.com/getsentry/self-hosted/issues/3614 for reported issue - $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx find /var/www/js-sdk -type d -exec chmod 755 {} \; - $dcr --no-deps --rm -v "sentry-nginx-www:/var/www" nginx find /var/www/js-sdk -type f -exec chmod 644 {} \; + $dcr --no-deps nginx find /var/www/js-sdk -type d -exec chmod 755 {} \; + $dcr --no-deps nginx find /var/www/js-sdk -type f -exec chmod 644 {} \; echo "${_endgroup}" fi From 4123963817ee545cd7c4c03e578a1ef28136520b Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 18 Jun 2025 19:40:07 +0000 Subject: [PATCH 181/305] build: Set master version to nightly #skip-changelog --- .env | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 2a80e2b330e..a73d4dd4ba7 100644 --- a/.env +++ b/.env @@ -9,12 +9,12 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.6.0 -SNUBA_IMAGE=getsentry/snuba:25.6.0 -RELAY_IMAGE=getsentry/relay:25.6.0 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.6.0 -TASKBROKER_IMAGE=getsentry/taskbroker:25.6.0 -VROOM_IMAGE=getsentry/vroom:25.6.0 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +TASKBROKER_IMAGE=getsentry/taskbroker:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 43d7d967212f8a910af3c389ac7f47e3aae5c93b Mon Sep 17 00:00:00 2001 From: yildizozgur Date: Thu, 19 Jun 2025 03:07:12 +0200 Subject: [PATCH 182/305] feat: enable customization sentry DSN endpoint (#3747) feat: enable customization sentry DSN endpoint Update sentry/sentry.conf.example.py --- sentry/sentry.conf.example.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 79c7aefa6cd..ed30ad0a67f 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -341,6 +341,14 @@ def get_internal_network(): # https://django-csp.readthedocs.io/en/latest/configuration.html # CSP_SCRIPT_SRC += ["example.com"] +############################ +# Sentry Endpoint Settings # +############################ + +# URI Prefixes for generating DSN URLs +# (default is URL_PREFIX) +# SENTRY_ENDPOINT = "https://sentry.ingest.example.com" + ################# # CSRF Settings # ################# From d80a7d9c86cd290c36b4d64a26fbb438a408c6ad Mon Sep 17 00:00:00 2001 From: Mark Story Date: Thu, 19 Jun 2025 09:56:46 -0400 Subject: [PATCH 183/305] fix(taskworker) Remove num-brokers (#3769) The num-brokers option generates broker host names that don't exist in self-hosted. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 70c9327dfe6..65bee636869 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -500,7 +500,7 @@ services: command: run taskworker-scheduler taskworker: <<: *sentry_defaults - command: run taskworker --concurrency=4 --rpc-host=taskbroker:50051 --num-brokers=1 + command: run taskworker --concurrency=4 --rpc-host=taskbroker:50051 vroom: <<: *restart_policy image: "$VROOM_IMAGE" From c794a189d04870d37e9872d0353531b89b94973d Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Fri, 20 Jun 2025 22:34:01 +0000 Subject: [PATCH 184/305] release: 25.6.1 --- .env | 12 ++++++------ CHANGELOG.md | 10 ++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.env b/.env index a73d4dd4ba7..3a52ecfc705 100644 --- a/.env +++ b/.env @@ -9,12 +9,12 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -TASKBROKER_IMAGE=getsentry/taskbroker:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.6.1 +SNUBA_IMAGE=getsentry/snuba:25.6.1 +RELAY_IMAGE=getsentry/relay:25.6.1 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.6.1 +TASKBROKER_IMAGE=getsentry/taskbroker:25.6.1 +VROOM_IMAGE=getsentry/vroom:25.6.1 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1460ee3a644..d5db9bd0166 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 25.6.1 + +### Various fixes & improvements + +- fix(taskworker) Remove num-brokers (#3769) by @markstory +- feat: enable customization sentry DSN endpoint (#3747) by @yildizozgur +- ref(js-assets): Simplify how we call nginx container (#3761) by @BYK +- Revert "fix(vroom): Explicitly set PROFILES_DIR for upcoming change" (#3760) by @hubertdeng123 +- fix(vroom): Explicitly set PROFILES_DIR for upcoming change (#3759) by @BYK + ## 25.6.0 ### Various fixes & improvements From 494051b8df0c6e18badb701daf85b3818c170888 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Fri, 20 Jun 2025 22:45:39 +0000 Subject: [PATCH 185/305] build: Set master version to nightly #skip-changelog --- .env | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 3a52ecfc705..a73d4dd4ba7 100644 --- a/.env +++ b/.env @@ -9,12 +9,12 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.6.1 -SNUBA_IMAGE=getsentry/snuba:25.6.1 -RELAY_IMAGE=getsentry/relay:25.6.1 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.6.1 -TASKBROKER_IMAGE=getsentry/taskbroker:25.6.1 -VROOM_IMAGE=getsentry/vroom:25.6.1 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +TASKBROKER_IMAGE=getsentry/taskbroker:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 0fce96cc112e25800cda22d7941794c88f2cba38 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 26 Jun 2025 05:07:43 +0700 Subject: [PATCH 186/305] chore: provide detailed note for sentry endpoint settings (#3780) Follow up for https://github.com/getsentry/self-hosted/pull/3747 --- sentry/sentry.conf.example.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index ed30ad0a67f..85f55906f76 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -345,8 +345,12 @@ def get_internal_network(): # Sentry Endpoint Settings # ############################ -# URI Prefixes for generating DSN URLs -# (default is URL_PREFIX) +# If your Sentry installation has different hostnames for ingestion and web UI, +# in which your web UI is accessible via private corporate network, yet your +# ingestion hostname is accessible from the public internet, you can uncomment +# this following options in order to have the ingestion hostname rendered +# correctly on the SDK configuration UI. +# # SENTRY_ENDPOINT = "https://sentry.ingest.example.com" ################# From bf660f3302e6e96d7e0dc47b91e42ad3fc1e2a56 Mon Sep 17 00:00:00 2001 From: Tobias Wilfert <36408720+tobias-wilfert@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:12:13 +0200 Subject: [PATCH 187/305] fix: Increase timeout for flakey test (#3781) --- _integration-test/test_01_basics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_integration-test/test_01_basics.py b/_integration-test/test_01_basics.py index 741d4fd807c..14ffa253067 100644 --- a/_integration-test/test_01_basics.py +++ b/_integration-test/test_01_basics.py @@ -22,7 +22,7 @@ SENTRY_TEST_HOST = os.getenv("SENTRY_TEST_HOST", "http://localhost:9000") TEST_USER = "test@example.com" TEST_PASS = "test123TEST" -TIMEOUT_SECONDS = 60 +TIMEOUT_SECONDS = 120 def poll_for_response( From fa34d4922a774c8489019fccc5fca49dc1397002 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 30 Jun 2025 22:18:12 +0000 Subject: [PATCH 188/305] release: 25.6.2 --- .env | 12 ++++++------ CHANGELOG.md | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.env b/.env index a73d4dd4ba7..ff49588ae70 100644 --- a/.env +++ b/.env @@ -9,12 +9,12 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -TASKBROKER_IMAGE=getsentry/taskbroker:nightly -VROOM_IMAGE=getsentry/vroom:nightly +SENTRY_IMAGE=getsentry/sentry:25.6.2 +SNUBA_IMAGE=getsentry/snuba:25.6.2 +RELAY_IMAGE=getsentry/relay:25.6.2 +SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.6.2 +TASKBROKER_IMAGE=getsentry/taskbroker:25.6.2 +VROOM_IMAGE=getsentry/vroom:25.6.2 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index d5db9bd0166..3f90ca37103 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 25.6.2 + +### Various fixes & improvements + +- fix: Increase timeout for flakey test (#3781) by @tobias-wilfert +- chore: provide detailed note for sentry endpoint settings (#3780) by @aldy505 + ## 25.6.1 ### Various fixes & improvements From acbdee40df6d4ecf9eb4645ac5b45ec739f537cf Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 30 Jun 2025 22:47:22 +0000 Subject: [PATCH 189/305] build: Set master version to nightly #skip-changelog --- .env | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index ff49588ae70..a73d4dd4ba7 100644 --- a/.env +++ b/.env @@ -9,12 +9,12 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:25.6.2 -SNUBA_IMAGE=getsentry/snuba:25.6.2 -RELAY_IMAGE=getsentry/relay:25.6.2 -SYMBOLICATOR_IMAGE=getsentry/symbolicator:25.6.2 -TASKBROKER_IMAGE=getsentry/taskbroker:25.6.2 -VROOM_IMAGE=getsentry/vroom:25.6.2 +SENTRY_IMAGE=getsentry/sentry:nightly +SNUBA_IMAGE=getsentry/snuba:nightly +RELAY_IMAGE=getsentry/relay:nightly +SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly +TASKBROKER_IMAGE=getsentry/taskbroker:nightly +VROOM_IMAGE=getsentry/vroom:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From b5a0158871daf6b0e1c7dd5a3b8437bc2c118735 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 2 Jul 2025 15:30:20 +0700 Subject: [PATCH 190/305] ci: run tests on arm64 (#3750) * ci: run tests on arm64 * ci: runner name should be arm, not arm64 * ci: retain old job name to not mess with CI protection rules * ci: integration test should not use plural form --- .github/workflows/test.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 672a2802e78..e02e81eb1f8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,8 +21,11 @@ defaults: jobs: unit-test: if: github.repository_owner == 'getsentry' - runs-on: ubuntu-22.04 - name: "unit tests" + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-24.04, ubuntu-24.04-arm] + name: ${{ matrix.os == 'ubuntu-24.04-arm' && 'unit tests (arm64)' || 'unit tests' }} steps: - name: Checkout uses: actions/checkout@v4 @@ -35,8 +38,11 @@ jobs: integration-test: if: github.repository_owner == 'getsentry' - runs-on: ubuntu-22.04 - name: integration test + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-24.04, ubuntu-24.04-arm] + name: ${{ matrix.os == 'ubuntu-24.04-arm' && 'integration test (arm64)' || 'integration test' }} env: REPORT_SELF_HOSTED_ISSUES: 0 SELF_HOSTED_TESTING_DSN: ${{ vars.SELF_HOSTED_TESTING_DSN }} From d3a068df8407825af694c5e4b416ef392aa817f2 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 2 Jul 2025 16:12:47 +0700 Subject: [PATCH 191/305] feat: make `system.secret-key` configurable from environment variables (#3783) --- sentry/config.example.yml | 3 +++ sentry/sentry.conf.example.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/sentry/config.example.yml b/sentry/config.example.yml index 54fe0c9c813..3c499e7a625 100644 --- a/sentry/config.example.yml +++ b/sentry/config.example.yml @@ -52,6 +52,9 @@ system.internal-url-prefix: 'http://web:9000' # If this file ever becomes compromised, it's important to generate a new key. # Changing this value will result in all current sessions being invalidated. # A new key can be generated with `$ sentry config generate-secret-key` +# +# If you are using SENTRY_SYSTEM_SECRET_KEY that is being set on your `.env` or `.env.custom` file, +# you should remove this line below as it won't be used anyway. system.secret-key: '!!changeme!!' # The ``redis.clusters`` setting is used, unsurprisingly, to configure Redis diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 85f55906f76..4b69c32e870 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -64,10 +64,25 @@ def get_internal_network(): # and thus various UI optimizations should be enabled. SENTRY_SINGLE_ORGANIZATION = True +# Sentry event retention days specifies how long events are retained in the database. +# This should be set on your `.env` or `.env.custom` file, instead of modifying +# the value here. +# NOTE: The longer the days, the more disk space is required. SENTRY_OPTIONS["system.event-retention-days"] = int( env("SENTRY_EVENT_RETENTION_DAYS", "90") ) +# The secret key is being used for various cryptographic operations, such as +# generating a CSRF token, session token, and registering Relay instances. +# The secret key value should be set on your `.env` or `.env.custom` file +# instead of modifying the value here. +# +# If the key ever becomes compromised, it's important to generate a new key. +# Changing this value will result in all current sessions being invalidated. +# A new key can be generated with `$ sentry config generate-secret-key` +if env("SENTRY_SYSTEM_SECRET_KEY"): + SENTRY_OPTIONS["system.secret-key"] = env("SENTRY_SYSTEM_SECRET_KEY", "") + # Self-hosted Sentry infamously has a lot of Docker containers required to make # all the features work. Oftentimes, users don't use the full feature set that # requires all the containers. This is a way to enable only the error monitoring From 06d0fb1715ae10ea9a9757f4ebc2e6be2cc64a6e Mon Sep 17 00:00:00 2001 From: Evan Purkhiser Date: Mon, 7 Jul 2025 12:23:50 -0400 Subject: [PATCH 192/305] feat(uptime): Enable uptime in self-hosted (#3787) --- .env | 1 + docker-compose.yml | 32 ++++++++++++++++++++++++++++++++ sentry/sentry.conf.example.py | 15 +++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/.env b/.env index a73d4dd4ba7..bb616638144 100644 --- a/.env +++ b/.env @@ -15,6 +15,7 @@ RELAY_IMAGE=getsentry/relay:nightly SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly TASKBROKER_IMAGE=getsentry/taskbroker:nightly VROOM_IMAGE=getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/docker-compose.yml b/docker-compose.yml index 65bee636869..c75376c5964 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -305,6 +305,11 @@ services: command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset profiles: - feature-complete + snuba-uptime-results-consumer: + <<: *snuba_defaults + command: rust-consumer --storage uptime_monitor_checks --consumer-group snuba-uptime-results --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + profiles: + - feature-complete symbolicator: <<: *restart_policy image: "$SYMBOLICATOR_IMAGE" @@ -415,6 +420,11 @@ services: command: run consumer monitors-clock-tasks --consumer-group monitors-clock-tasks profiles: - feature-complete + uptime-results: + <<: *sentry_defaults + command: run consumer uptime-results --consumer-group uptime-results + profiles: + - feature-complete post-process-forwarder-transactions: <<: *sentry_defaults command: run consumer --no-strict-offset-reset post-process-forwarder-transactions --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-transactions-commit-log --synchronize-commit-group transactions_group @@ -533,6 +543,28 @@ services: - sentry-vroom:/var/vroom/sentry-profiles profiles: - feature-complete + uptime-checker: + <<: *restart_policy + image: "$UPTIME_CHECKER_IMAGE" + command: run + environment: + UPTIME_CHECKER_RESULTS_KAFKA_CLUSTER: kafka:9092 + UPTIME_CHECKER_REDIS_HOST: redis://redis:6379 + # Set to `true` will allow uptime checks against private IP addresses + UPTIME_CHECKER_ALLOW_INTERNAL_IPS: "false" + # The number of times to retry failed checks before reporting them as failed + UPTIME_CHECKER_FAILURE_RETRIES: "1" + # DNS name servers to use when making checks in the http checker. + # Separated by commas. Leaving this unset will default to the systems dns + # resolver. + #UPTIME_CHECKER_HTTP_CHECKER_DNS_NAMESERVERS: "8.8.8.8,8.8.4.4" + depends_on: + kafka: + <<: *depends_on-healthy + redis: + <<: *depends_on-healthy + profiles: + - feature-complete volumes: # These store application data that should persist across restarts. diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 4b69c32e870..c8a4afbbd21 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -329,9 +329,24 @@ def get_internal_network(): "organizations:continuous-profiling", "organizations:continuous-profiling-stats", ) + # Uptime related flags + + ( + "organizations:uptime", + "organizations:uptime-create-issues", + # TODO(epurkhiser): We can remove remove these in 25.8.0 since + # we'll have released this issue group type + # (https://github.com/getsentry/sentry/pull/94827) + "organizations:issue-uptime-domain-failure-visible", + "organizations:issue-uptime-domain-failure-ingest", + "organizations:issue-uptime-domain-failure-post-process-group", + ) } ) +# TODO(epurkhiser): In 25.8.0 we can drop this option override as we've made it +# default in sentry (https://github.com/getsentry/sentry/pull/94822) +SENTRY_OPTIONS["uptime.snuba_uptime_results.enabled"] = True + ####################### # MaxMind Integration # ####################### From e2ad04d564385f05e6dfbc62c7ff1c16d5a81297 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 8 Jul 2025 08:42:50 +0700 Subject: [PATCH 193/305] feat: run EAP-related containers (#3778) * feat: run snuba-items consumer * feat: remove process-spans as it turns out relay does not publish to that topic yet * feat: try re-adding process-spans * feat: add snuba subscriptions-scheduler-executor for eap_items * feat: run process-segment sentry consumer --------- Co-authored-by: Burak Yigit Kaya --- docker-compose.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index c75376c5964..8d66a5f21a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -305,6 +305,14 @@ services: command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset profiles: - feature-complete + snuba-eap-items-consumer: + <<: *snuba_defaults + command: rust-consumer --storage eap_items --consumer-group eap_items_group --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --use-rust-processor + profiles: + - feature-complete + snuba-subscription-consumer-eap-items: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset events_analytics_platform --entity eap_items --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-eap-items-subscriptions-consumers --followed-consumer-group=eap_items_group --schedule-ttl=60 --stale-threshold-seconds=900 snuba-uptime-results-consumer: <<: *snuba_defaults command: rust-consumer --storage uptime_monitor_checks --consumer-group snuba-uptime-results --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset @@ -410,6 +418,16 @@ services: command: run consumer ingest-feedback-events --consumer-group ingest-feedback profiles: - feature-complete + process-spans: + <<: *sentry_defaults + command: run consumer --no-strict-offset-reset process-spans --consumer-group process-spans + profiles: + - feature-complete + process-segments: + <<: *sentry_defaults + command: run consumer --no-strict-offset-reset process-segments --consumer-group process-segments + profiles: + - feature-complete monitors-clock-tick: <<: *sentry_defaults command: run consumer monitors-clock-tick --consumer-group monitors-clock-tick @@ -440,6 +458,11 @@ services: command: run consumer transactions-subscription-results --consumer-group query-subscription-consumer profiles: - feature-complete + subscription-consumer-eap-items: + <<: *sentry_defaults + command: run consumer subscription-results-eap-items --consumer-group subscription-results-eap-items + profiles: + - feature-complete subscription-consumer-metrics: <<: *sentry_defaults command: run consumer metrics-subscription-results --consumer-group query-subscription-consumer From 0c63bec2433f291c61eaa14ac22ebb896f30e1bd Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 10 Jul 2025 06:27:09 +0700 Subject: [PATCH 194/305] docs: encourage community patches (#3794) Hopefully this will provide a better guide on how to create patches. --- optional-modifications/README.md | 51 ++++++++------- optional-modifications/_lib.sh | 15 ----- .../external-kafka/docker-compose.yml.patch | 62 +++++++++++++++++-- 3 files changed, 86 insertions(+), 42 deletions(-) delete mode 100755 optional-modifications/_lib.sh diff --git a/optional-modifications/README.md b/optional-modifications/README.md index 84cf7e0e2b9..054942138de 100644 --- a/optional-modifications/README.md +++ b/optional-modifications/README.md @@ -1,11 +1,10 @@ # Optional Modifications -Other than the default self-hosted Sentry installation, sometimes users -can leverage their existing infrastructure to help them with limited -resources. "Patches", or you might call this like a "plugin system", is -a collection of patch files (see [man patch(1)](https://man7.org/linux/man-pages/man1/patch.1.html)) -that can be used with to modify the existing configuration to achieve -the desired goal. +While the default self-hosted Sentry installation is often sufficient, there are instances where leveraging existing infrastructure becomes a practical necessity, particularly for users with limited resources. This is where **patches**, or what can be understood as a **plugin system**, come into play. + +A patch system comprises a collection of patch files (refer to man patch(1) for detailed information) designed to modify an existing Sentry configuration. This allows for targeted adjustments to achieve specific operational goals, optimizing Sentry's functionality within your current environment. This approach provides a flexible alternative to a full, customized re-installation, enabling users to adapt Sentry to their specific needs with greater efficiency. + +We also actively encourage the community to contribute! If you've developed a patch that enhances your self-hosted Sentry experience, consider submitting a pull request. Your contributions can be invaluable to other users facing similar challenges, fostering a collaborative environment where shared solutions benefit everyone. > [!WARNING] > Beware that this is very experimental and might not work as expected. @@ -14,28 +13,38 @@ the desired goal. ## How to use patches -The patches are designed mostly to help modify the existing -configuration files. You will need to run the `install.sh` script -afterwards. +The patches are designed mostly to help modify the existing configuration files. You will need to run the `install.sh` script afterwards. -They should be run from the root directory. For example, the -`external-kafka` patches should be run as: +They should be run from the root directory. For example, the `external-kafka` patches should be run as: ```bash -patch < optional-modifications/patches/external-kafka/.env.patch -patch < optional-modifications/patches/external-kafka/config.example.yml.patch -patch < optional-modifications/patches/external-kafka/sentry.conf.example.py.patch -patch < optional-modifications/patches/external-kafka/docker-compose.yml.patch +patch -p0 < optional-modifications/patches/external-kafka/.env.patch +patch -p0 < optional-modifications/patches/external-kafka/config.example.yml.patch +patch -p0 < optional-modifications/patches/external-kafka/sentry.conf.example.py.patch +patch -p0 < optional-modifications/patches/external-kafka/docker-compose.yml.patch ``` -Some patches might require additional steps to be taken, like providing -credentials or additional TLS certificates. +The `-p0` flag is important to ensure the patch applies to the correct absolute file path. + +Some patches might require additional steps to be taken, like providing credentials or additional TLS certificates. Make sure to see your changed files before running the `install.sh` script. + +## How to create patches + +1. Copy the original file to a temporary file name. For example, if you want to create a `clustered-redis` patch, you might want to copy `docker-compose.yml` to `docker-compose.clustered-redis.yml`. +2. Make your changes on the `docker-compose.clustered-redis.yml` file. +3. Run the following command to create the patch: + ```bash + diff -Naru docker-compose.yml docker-compose.clustered-redis.yml > docker-compose.yml.patch + ``` + Or the template command: + ```bash + diff -Naru [original file] [patched file] > [destination file].patch + ``` +4. Create a new directory in the `optional-modifications/patches` folder with the name of the patch. For example, `optional-modifications/patches/clustered-redis`. +5. Move the patched files (like `docker-compose.yml.patch` earlier) into the new directory. ## Official support -Sentry employees are not obliged to provide dedicated support for -patches, but they can help by providing information to move us forward. -We encourage the community to contribute for any bug fixes or -improvements. +While Sentry employees aren't able to offer dedicated support for these patches, they can provide valuable information to help move things forward. Ultimately, we really encourage the community to take the wheel, maintaining and fostering these patches themselves. If you have questions, Sentry employees will be there to help guide you. See the [support policy for self-hosted Sentry](https://develop.sentry.dev/self-hosted/support/) for more information. diff --git a/optional-modifications/_lib.sh b/optional-modifications/_lib.sh deleted file mode 100755 index 46e55d3e257..00000000000 --- a/optional-modifications/_lib.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -test "${DEBUG:-}" && set -x - -function patch_file() { - target="$1" - content="$2" - if [[ -f "$target" ]]; then - echo "🙈 Patching $target ..." - patch -p1 <"$content" - else - echo "🙊 Skipping $target ..." - fi -} diff --git a/optional-modifications/patches/external-kafka/docker-compose.yml.patch b/optional-modifications/patches/external-kafka/docker-compose.yml.patch index cd669acc784..7f2561cce67 100644 --- a/optional-modifications/patches/external-kafka/docker-compose.yml.patch +++ b/optional-modifications/patches/external-kafka/docker-compose.yml.patch @@ -1,5 +1,5 @@ ---- docker-compose.yml 2025-03-17 13:32:15.120328412 +0700 -+++ docker-compose.external-kafka.yml 2025-05-15 08:39:05.509951068 +0700 +--- docker-compose.yml 2025-07-08 10:22:36.600616503 +0700 ++++ docker-compose.external-kafka.yml 2025-07-08 10:36:44.069900011 +0700 @@ -26,8 +26,6 @@ depends_on: redis: @@ -48,7 +48,7 @@ REDIS_HOST: redis UWSGI_MAX_REQUESTS: "10000" UWSGI_DISABLE_LOGGING: "true" -@@ -140,43 +151,7 @@ +@@ -136,43 +147,7 @@ POSTGRES_HOST_AUTH_METHOD: "trust" volumes: - "sentry-postgres:/var/lib/postgresql/data" @@ -93,7 +93,7 @@ clickhouse: <<: *restart_policy image: clickhouse-self-hosted-local -@@ -475,9 +450,8 @@ +@@ -509,9 +484,8 @@ read_only: true source: ./geoip target: /geoip @@ -104,7 +104,32 @@ redis: <<: *depends_on-healthy web: -@@ -486,15 +460,21 @@ +@@ -520,8 +494,22 @@ + <<: *restart_policy + image: "$TASKBROKER_IMAGE" + environment: +- TASKBROKER_KAFKA_CLUSTER: "kafka:9092" +- TASKBROKER_KAFKA_DEADLETTER_CLUSTER: "kafka:9092" ++ TASKBROKER_KAFKA_CLUSTER: ${KAFKA_BOOTSTRAP_SERVERS:-kafka:9092} ++ TASKBROKER_KAFKA_SECURITY_PROTOCOL: ${KAFKA_SECURITY_PROTOCOL:-PLAINTEXT} ++ TASKBROKER_KAFKA_SSL_CA_LOCATION: ${KAFKA_SSL_CA_LOCATION:-} ++ TASKBROKER_KAFKA_SSL_CERTIFICATE_LOCATION: ${KAFKA_SSL_CERTIFICATE_LOCATION:-} ++ TASKBROKER_KAFKA_SSL_KEY_LOCATION: ${KAFKA_SSL_KEY_LOCATION:-} ++ TASKBROKER_KAFKA_SASL_MECHANISM: ${KAFKA_SASL_MECHANISM:-} ++ TASKBROKER_KAFKA_SASL_USERNAME: ${KAFKA_SASL_USERNAME:-} ++ TASKBROKER_KAFKA_SASL_PASSWORD: ${KAFKA_SASL_PASSWORD:-} ++ TASKBROKER_KAFKA_DEADLETTER_CLUSTER: ${KAFKA_BOOTSTRAP_SERVERS:-kafka:9092} ++ TASKBROKER_KAFKA_DEADLETTER_SECURITY_PROTOCOL: ${KAFKA_SECURITY_PROTOCOL:-PLAINTEXT} ++ TASKBROKER_KAFKA_DEADLETTER_SSL_CA_LOCATION: ${KAFKA_SSL_CA_LOCATION:-} ++ TASKBROKER_KAFKA_DEADLETTER_SSL_CERTIFICATE_LOCATION: ${KAFKA_SSL_CERTIFICATE_LOCATION:-} ++ TASKBROKER_KAFKA_DEADLETTER_SSL_KEY_LOCATION: ${KAFKA_SSL_KEY_LOCATION:-} ++ TASKBROKER_KAFKA_DEADLETTER_SASL_MECHANISM: ${KAFKA_SASL_MECHANISM:-} ++ TASKBROKER_KAFKA_DEADLETTER_SASL_USERNAME: ${KAFKA_SASL_USERNAME:-} ++ TASKBROKER_KAFKA_DEADLETTER_SASL_PASSWORD: ${KAFKA_SASL_PASSWORD:-} + TASKBROKER_DB_PATH: "/opt/sqlite/taskbroker-activations.sqlite" + volumes: + - sentry-taskbroker:/opt/sqlite +@@ -538,15 +526,21 @@ <<: *restart_policy image: "$VROOM_IMAGE" environment: @@ -131,7 +156,32 @@ profiles: - feature-complete vroom-cleanup: -@@ -523,8 +503,6 @@ +@@ -571,7 +565,14 @@ + image: "$UPTIME_CHECKER_IMAGE" + command: run + environment: +- UPTIME_CHECKER_RESULTS_KAFKA_CLUSTER: kafka:9092 ++ UPTIME_CHECKER_RESULTS_KAFKA_CLUSTER: ${KAFKA_BOOTSTRAP_SERVERS:-kafka:9092} ++ UPTIME_CHECKER_KAFKA_SECURITY_PROTOCOL: ${KAFKA_SECURITY_PROTOCOL:-PLAINTEXT} ++ UPTIME_CHECKER_KAFKA_SSL_CA_LOCATION: ${KAFKA_SSL_CA_LOCATION:-} ++ UPTIME_CHECKER_KAFKA_SSL_CERT_LOCATION: ${KAFKA_SSL_CERTIFICATE_LOCATION:-} ++ UPTIME_CHECKER_KAFKA_SSL_KEY_LOCATION: ${KAFKA_SSL_KEY_LOCATION:-} ++ UPTIME_CHECKER_KAFKA_SASL_MECHANISM: ${KAFKA_SASL_MECHANISM:-} ++ UPTIME_CHECKER_KAFKA_SASL_USERNAME: ${KAFKA_SASL_USERNAME:-} ++ UPTIME_CHECKER_KAFKA_SASL_PASSWORD: ${KAFKA_SASL_PASSWORD:-} + UPTIME_CHECKER_REDIS_HOST: redis://redis:6379 + # Set to `true` will allow uptime checks against private IP addresses + UPTIME_CHECKER_ALLOW_INTERNAL_IPS: "false" +@@ -582,8 +583,6 @@ + # resolver. + #UPTIME_CHECKER_HTTP_CHECKER_DNS_NAMESERVERS: "8.8.8.8,8.8.4.4" + depends_on: +- kafka: +- <<: *depends_on-healthy + redis: + <<: *depends_on-healthy + profiles: +@@ -597,8 +596,6 @@ external: true sentry-redis: external: true From 9d710cda43d3433bc6ac9ce1f96e94f5f4aed093 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Thu, 10 Jul 2025 17:42:50 -0700 Subject: [PATCH 195/305] feat(images):Cutover images to ghcr (#3800) cutover to ghcr --- .env | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env b/.env index bb616638144..ee11f6bd67a 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=getsentry/sentry:nightly -SNUBA_IMAGE=getsentry/snuba:nightly -RELAY_IMAGE=getsentry/relay:nightly -SYMBOLICATOR_IMAGE=getsentry/symbolicator:nightly -TASKBROKER_IMAGE=getsentry/taskbroker:nightly -VROOM_IMAGE=getsentry/vroom:nightly -UPTIME_CHECKER_IMAGE=getsentry/uptime-checker:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 3e9e1ec367c7c45d6eb794e8763009ea83f16eac Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 11 Jul 2025 22:19:14 +0700 Subject: [PATCH 196/305] fix: set harakiri Django option to 30s (#3792) * fix: set harakiri Django option to 30s Closes https://github.com/getsentry/self-hosted/issues/1573 From @guoard and @aminvakil who found the issue of "uWSGI reports full listen queue" was caused mostly by workers taking longer times to finish. For folks with bigger Sentry installation, they might want to increase the `proxy_read_timeout` and `harakiri` values to a longer (acceptable) time. See the GitHub issue linked above for more details. * feat: document 'harakiri' option instead of making it the default * Update sentry.conf.example.py Co-authored-by: Amin Vakil * Update sentry.conf.example.py Co-authored-by: Amin Vakil --------- Co-authored-by: Amin Vakil --- sentry/sentry.conf.example.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index c8a4afbbd21..a082246c734 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -230,6 +230,12 @@ def get_internal_network(): "workers": 3, "threads": 4, "memory-report": False, + # The `harakiri` option terminates requests that take longer than the + # defined amount of time (in seconds) which can help avoid stuck workers + # caused by GIL issues or deadlocks. + # Ensure nginx `proxy_read_timeout` configuration (default: 30) + # on your `nginx.conf` file to be at least 5 seconds longer than this. + # "harakiri": 25, # Some stuff so uwsgi will cycle workers sensibly "max-requests": 100000, "max-requests-delta": 500, From 91b42a9878ecb960116cfe553ccbfdb4cbb4977b Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 14 Jul 2025 20:49:21 +0700 Subject: [PATCH 197/305] feat: Swap `trace-view-v1` feature flag with `visibility-explore-view` (#3801) --- sentry/sentry.conf.example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index a082246c734..19c58ce5ee3 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -304,7 +304,7 @@ def get_internal_network(): "organizations:dashboards-rh-widget", "organizations:metrics-extraction", "organizations:transaction-metrics-extraction", - "organizations:trace-view-v1", + "organizations:visibility-explore-view", "organizations:dynamic-sampling", "projects:custom-inbound-filters", "projects:data-forwarding", From db2363e2185dbd792d736e4c04c6521baecc512e Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 16 Jul 2025 05:58:08 +0000 Subject: [PATCH 198/305] release: 25.7.0 --- .env | 12 ++++++------ CHANGELOG.md | 13 +++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.env b/.env index ee11f6bd67a..27fcd3202ba 100644 --- a/.env +++ b/.env @@ -9,12 +9,12 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly -SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly -RELAY_IMAGE=ghcr.io/getsentry/relay:nightly -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly -VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.7.0 +SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.7.0 +RELAY_IMAGE=ghcr.io/getsentry/relay:25.7.0 +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.7.0 +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.7.0 +VROOM_IMAGE=ghcr.io/getsentry/vroom:25.7.0 UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f90ca37103..ea0deec5a96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 25.7.0 + +### Various fixes & improvements + +- feat: Swap `trace-view-v1` feature flag with `visibility-explore-view` (#3801) by @aldy505 +- fix: set harakiri Django option to 30s (#3792) by @aldy505 +- feat(images):Cutover images to ghcr (#3800) by @hubertdeng123 +- docs: encourage community patches (#3794) by @aldy505 +- feat: run EAP-related containers (#3778) by @aldy505 +- feat(uptime): Enable uptime in self-hosted (#3787) by @evanpurkhiser +- feat: make `system.secret-key` configurable from environment variables (#3783) by @aldy505 +- ci: run tests on arm64 (#3750) by @aldy505 + ## 25.6.2 ### Various fixes & improvements From 0f2748e85c07b53903c421c7e3dbfbb5be2b0ebb Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 16 Jul 2025 06:10:22 +0000 Subject: [PATCH 199/305] build: Set master version to nightly #skip-changelog --- .env | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 27fcd3202ba..ee11f6bd67a 100644 --- a/.env +++ b/.env @@ -9,12 +9,12 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.7.0 -SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.7.0 -RELAY_IMAGE=ghcr.io/getsentry/relay:25.7.0 -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.7.0 -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.7.0 -VROOM_IMAGE=ghcr.io/getsentry/vroom:25.7.0 +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s From 9fbd722d4449276332de041f9c0d99eb60f80e10 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 19 Jul 2025 12:25:35 +0700 Subject: [PATCH 200/305] feat: inspect docker compose failure on self-hosted e2e action (#3817) It's hard to debug docker compose failure on other repositories since they can't see the `docker compose ps` and `docker compose logs`. One problem occurred here: https://github.com/getsentry/relay/pull/4940 This PR aims to provide both commands if failure happens. --- .github/workflows/test.yml | 6 ------ action.yaml | 11 +++++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e02e81eb1f8..016fd7f0b93 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,9 +54,3 @@ jobs: uses: './' with: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - - - name: Inspect failure - if: failure() - run: | - docker compose ps - docker compose logs diff --git a/action.yaml b/action.yaml index ebc22f4831c..8da5c2966db 100644 --- a/action.yaml +++ b/action.yaml @@ -168,3 +168,14 @@ runs: with: directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} + + - name: Inspect failure + if: failure() + shell: bash + run: | + echo "::group::Inspect failure - docker compose ps" + docker compose ps + echo "::endgroup::" + echo "::group::Inspect failure - docker compose logs" + docker compose logs + echo "::endgroup::" From a2447aa4805abf0e58ceb0ca3dde5cf4ce7ee48a Mon Sep 17 00:00:00 2001 From: Nikita Korolev <66738864+doc-sheet@users.noreply.github.com> Date: Sun, 20 Jul 2025 03:04:09 +0300 Subject: [PATCH 201/305] Cleanup unused feature flags (#3820) * remove organizations:sso-rippling https://github.com/getsentry/sentry/pull/31515 * remove organizations:metrics-extraction https://github.com/getsentry/sentry/pull/69860 * remove organizations:user-feedback-ingest https://github.com/getsentry/sentry/pull/78097 * remove organizations:user-feedback-replay-clip https://github.com/getsentry/sentry/pull/87771 --------- Co-authored-by: ds --- sentry/sentry.conf.example.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 19c58ce5ee3..0c8bb2b38df 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -291,7 +291,6 @@ def get_internal_network(): "organizations:integrations-issue-sync", "organizations:invite-members", "organizations:sso-basic", - "organizations:sso-rippling", "organizations:sso-saml2", "organizations:performance-view", "organizations:advanced-search", @@ -302,7 +301,6 @@ def get_internal_network(): "organizations:dashboards-mep", "organizations:mep-rollout-flag", "organizations:dashboards-rh-widget", - "organizations:metrics-extraction", "organizations:transaction-metrics-extraction", "organizations:visibility-explore-view", "organizations:dynamic-sampling", @@ -326,8 +324,6 @@ def get_internal_network(): ) # User Feedback related flags + ( - "organizations:user-feedback-ingest", - "organizations:user-feedback-replay-clip", "organizations:user-feedback-ui", ) # Continuous Profiling related flags From d696c202df499de0bcc80acde82baeb5440a99fd Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 22 Jul 2025 18:12:20 +0700 Subject: [PATCH 202/305] fix(action): missing project directory path for failure inspection (#3825) This one is missing. First seen here: https://github.com/getsentry/uptime-checker/actions/runs/16429015462/job/46426515654 --- action.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yaml b/action.yaml index 8da5c2966db..40b76283268 100644 --- a/action.yaml +++ b/action.yaml @@ -174,6 +174,7 @@ runs: shell: bash run: | echo "::group::Inspect failure - docker compose ps" + cd ${{ github.action_path }} docker compose ps echo "::endgroup::" echo "::group::Inspect failure - docker compose logs" From abe34d09ed8c2a24f067bfb00327539a866efb51 Mon Sep 17 00:00:00 2001 From: Daniel Bunte Date: Tue, 22 Jul 2025 15:58:07 +0200 Subject: [PATCH 203/305] feat(install): Adds support for podman(compose) (#3673) --- .github/workflows/test.yml | 16 ++++- docker-compose.yml | 10 +-- install/_detect-container-engine.sh | 12 ++++ install/_min-requirements.sh | 3 + install/build-docker-images.sh | 4 +- install/check-minimum-requirements.sh | 42 ++++++----- install/create-docker-volumes.sh | 23 +++++-- install/dc-detect-version.sh | 69 ++++++++++++++++--- install/detect-platform.sh | 12 ++-- ...ensure-correct-permissions-profiles-dir.sh | 2 + install/error-handling.sh | 8 +-- install/geoip.sh | 2 +- install/parse-cli.sh | 6 +- install/set-up-and-migrate-database.sh | 2 +- install/setup-js-sdk-assets.sh | 2 +- install/turn-things-off.sh | 11 ++- install/update-docker-images.sh | 22 +++--- install/upgrade-clickhouse.sh | 21 ++++-- install/upgrade-postgres.sh | 16 ++--- install/wrap-up.sh | 16 +++-- sentry-admin.sh | 4 +- 21 files changed, 224 insertions(+), 79 deletions(-) create mode 100644 install/_detect-container-engine.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 016fd7f0b93..e66f8668330 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,16 +40,30 @@ jobs: if: github.repository_owner == 'getsentry' runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ubuntu-24.04, ubuntu-24.04-arm] - name: ${{ matrix.os == 'ubuntu-24.04-arm' && 'integration test (arm64)' || 'integration test' }} + container_engine: ['docker'] # TODO: add 'podman' into the list + name: ${{ matrix.os == 'ubuntu-24.04-arm' && (matrix.container_engine == 'docker' && 'integration test (arm64)' || 'integration test (arm64 podman)') || (matrix.container_engine == 'docker' && 'integration test' || 'integration test (podman)') }} env: REPORT_SELF_HOSTED_ISSUES: 0 SELF_HOSTED_TESTING_DSN: ${{ vars.SELF_HOSTED_TESTING_DSN }} + CONTAINER_ENGINE_PODMAN: ${{ matrix.container_engine == 'podman' && '1' || '0' }} steps: - name: Checkout uses: actions/checkout@v4 + - name: Install Podman + if: matrix.container_engine == 'podman' + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends podman + # TODO: Replace below with podman-compose + # We need this commit to be able to work: https://github.com/containers/podman-compose/commit/8206cc3ea277eee6c2e87d4cd66eba8eae3d44eb + pip3 install --user https://github.com/containers/podman-compose/archive/main.tar.gz + echo "PODMAN_COMPOSE_PROVIDER=podman-compose" >> $GITHUB_ENV + echo "PODMAN_COMPOSE_WARNING_LOGS=false" >> $GITHUB_ENV + - name: Use action from local checkout uses: './' with: diff --git a/docker-compose.yml b/docker-compose.yml index 8d66a5f21a2..3373402c58a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,7 @@ x-restart-policy: &restart_policy restart: unless-stopped +x-pull-policy: &pull_policy + pull_policy: never x-depends_on-healthy: &depends_on-healthy condition: service_healthy x-depends_on-default: &depends_on-default @@ -15,7 +17,7 @@ x-healthcheck-defaults: &healthcheck_defaults retries: $HEALTHCHECK_RETRIES start_period: 10s x-sentry-defaults: &sentry_defaults - <<: *restart_policy + <<: [*restart_policy, *pull_policy] image: sentry-self-hosted-local # Set the platform to build for linux/arm64 when needed on Apple silicon Macs. platform: ${DOCKER_PLATFORM:-} @@ -174,7 +176,7 @@ services: timeout: 10s retries: 30 clickhouse: - <<: *restart_policy + <<: [*restart_policy, *pull_policy] image: clickhouse-self-hosted-local build: context: ./clickhouse @@ -329,7 +331,7 @@ services: target: /etc/symbolicator command: run -c /etc/symbolicator/config.yml symbolicator-cleanup: - <<: *restart_policy + <<: [*restart_policy, *pull_policy] image: symbolicator-cleanup-self-hosted-local build: context: ./cron @@ -550,7 +552,7 @@ services: profiles: - feature-complete vroom-cleanup: - <<: *restart_policy + <<: [*restart_policy, *pull_policy] image: vroom-cleanup-self-hosted-local build: context: ./cron diff --git a/install/_detect-container-engine.sh b/install/_detect-container-engine.sh new file mode 100644 index 00000000000..7fc23de2e2e --- /dev/null +++ b/install/_detect-container-engine.sh @@ -0,0 +1,12 @@ +echo "${_group}Detecting container engine ..." + +if [[ "${CONTAINER_ENGINE_PODMAN:-0}" -eq 1 ]] && command -v podman &>/dev/null; then + export CONTAINER_ENGINE="podman" +elif command -v docker &>/dev/null; then + export CONTAINER_ENGINE="docker" +else + echo "FAIL: Neither podman nor docker is installed on the system." + exit 1 +fi +echo "Detected container engine: $CONTAINER_ENGINE" +echo "${_endgroup}" diff --git a/install/_min-requirements.sh b/install/_min-requirements.sh index 17afa00995d..36c5dc0f625 100644 --- a/install/_min-requirements.sh +++ b/install/_min-requirements.sh @@ -2,6 +2,9 @@ MIN_DOCKER_VERSION='19.03.6' MIN_COMPOSE_VERSION='2.32.2' +MIN_PODMAN_VERSION='4.9.3' +MIN_PODMAN_COMPOSE_VERSION='1.3.0' + # 16 GB minimum host RAM, but there'll be some overhead outside of what # can be allotted to docker if [[ "$COMPOSE_PROFILES" == "errors-only" ]]; then diff --git a/install/build-docker-images.sh b/install/build-docker-images.sh index c793b9ea9c8..dce4c43ca4b 100644 --- a/install/build-docker-images.sh +++ b/install/build-docker-images.sh @@ -3,10 +3,10 @@ echo "${_group}Building and tagging Docker images ..." echo "" # Build any service that provides the image sentry-self-hosted-local first, # as it is used as the base image for sentry-cleanup-self-hosted-local. -$dcb --force-rm web +$dcb web # Build each other service individually to localize potential failures better. for service in $($dc config --services); do - $dcb --force-rm "$service" + $dcb "$service" done echo "" echo "Docker images built." diff --git a/install/check-minimum-requirements.sh b/install/check-minimum-requirements.sh index e06db42c48a..322de339759 100644 --- a/install/check-minimum-requirements.sh +++ b/install/check-minimum-requirements.sh @@ -2,31 +2,41 @@ echo "${_group}Checking minimum requirements ..." source install/_min-requirements.sh -DOCKER_VERSION=$(docker version --format '{{.Server.Version}}' || echo '') +DOCKER_VERSION=$($CONTAINER_ENGINE version --format '{{.Server.Version}}' || echo '') if [[ -z "$DOCKER_VERSION" ]]; then - echo "FAIL: Unable to get docker version, is the docker daemon running?" + echo "FAIL: Unable to get $CONTAINER_ENGINE version, is the $CONTAINER_ENGINE daemon running?" exit 1 fi -if ! vergte ${DOCKER_VERSION//v/} $MIN_DOCKER_VERSION; then - echo "FAIL: Expected minimum docker version to be $MIN_DOCKER_VERSION but found $DOCKER_VERSION" - exit 1 -fi -echo "Found Docker version $DOCKER_VERSION" - -if ! vergte ${COMPOSE_VERSION//v/} $MIN_COMPOSE_VERSION; then - echo "FAIL: Expected minimum $dc_base version to be $MIN_COMPOSE_VERSION but found $COMPOSE_VERSION" - exit 1 +if [[ "$CONTAINER_ENGINE" == "docker" ]]; then + if ! vergte ${DOCKER_VERSION//v/} $MIN_DOCKER_VERSION; then + echo "FAIL: Expected minimum docker version to be $MIN_DOCKER_VERSION but found $DOCKER_VERSION" + exit 1 + fi + if ! vergte ${COMPOSE_VERSION//v/} $MIN_COMPOSE_VERSION; then + echo "FAIL: Expected minimum $dc_base version to be $MIN_COMPOSE_VERSION but found $COMPOSE_VERSION" + exit 1 + fi +elif [[ "$CONTAINER_ENGINE" == "podman" ]]; then + if ! vergte ${DOCKER_VERSION//v/} $MIN_PODMAN_VERSION; then + echo "FAIL: Expected minimum podman version to be $MIN_PODMAN_VERSION but found $DOCKER_VERSION" + exit 1 + fi + if ! vergte ${COMPOSE_VERSION//v/} $MIN_PODMAN_COMPOSE_VERSION; then + echo "FAIL: Expected minimum $dc_base version to be $MIN_PODMAN_COMPOSE_VERSION but found $COMPOSE_VERSION" + exit 1 + fi fi -echo "Found Docker Compose version $COMPOSE_VERSION" +echo "Found $CONTAINER_ENGINE version $DOCKER_VERSION" +echo "Found $CONTAINER_ENGINE Compose version $COMPOSE_VERSION" -CPU_AVAILABLE_IN_DOCKER=$(docker run --rm busybox nproc --all) +CPU_AVAILABLE_IN_DOCKER=$($CONTAINER_ENGINE run --rm busybox nproc --all) if [[ "$CPU_AVAILABLE_IN_DOCKER" -lt "$MIN_CPU_HARD" ]]; then echo "FAIL: Required minimum CPU cores available to Docker is $MIN_CPU_HARD, found $CPU_AVAILABLE_IN_DOCKER" exit 1 fi -RAM_AVAILABLE_IN_DOCKER=$(docker run --rm busybox free -m 2>/dev/null | awk '/Mem/ {print $2}') +RAM_AVAILABLE_IN_DOCKER=$($CONTAINER_ENGINE run --rm busybox free -m 2>/dev/null | awk '/Mem/ {print $2}') if [[ "$RAM_AVAILABLE_IN_DOCKER" -lt "$MIN_RAM_HARD" ]]; then echo "FAIL: Required minimum RAM available to Docker is $MIN_RAM_HARD MB, found $RAM_AVAILABLE_IN_DOCKER MB" exit 1 @@ -35,9 +45,9 @@ fi #SSE4.2 required by Clickhouse (https://clickhouse.yandex/docs/en/operations/requirements/) # On KVM, cpuinfo could falsely not report SSE 4.2 support, so skip the check. https://github.com/ClickHouse/ClickHouse/issues/20#issuecomment-226849297 # This may also happen on other virtualization software such as on VMWare ESXi hosts. -IS_KVM=$(docker run --rm busybox grep -c 'Common KVM processor' /proc/cpuinfo || :) +IS_KVM=$($CONTAINER_ENGINE run --rm busybox grep -c 'Common KVM processor' /proc/cpuinfo || :) if [[ ! "$SKIP_SSE42_REQUIREMENTS" -eq 1 && "$IS_KVM" -eq 0 && "$DOCKER_ARCH" = "x86_64" ]]; then - SUPPORTS_SSE42=$(docker run --rm busybox grep -c sse4_2 /proc/cpuinfo || :) + SUPPORTS_SSE42=$($CONTAINER_ENGINE run --rm busybox grep -c sse4_2 /proc/cpuinfo || :) if [[ "$SUPPORTS_SSE42" -eq 0 ]]; then echo "FAIL: The CPU your machine is running on does not support the SSE 4.2 instruction set, which is required for one of the services Sentry uses (Clickhouse). See https://github.com/getsentry/self-hosted/issues/340 for more info." exit 1 diff --git a/install/create-docker-volumes.sh b/install/create-docker-volumes.sh index 15f20d54409..fdbecc2288b 100644 --- a/install/create-docker-volumes.sh +++ b/install/create-docker-volumes.sh @@ -1,10 +1,21 @@ echo "${_group}Creating volumes for persistent storage ..." -echo "Created $(docker volume create --name=sentry-clickhouse)." -echo "Created $(docker volume create --name=sentry-data)." -echo "Created $(docker volume create --name=sentry-kafka)." -echo "Created $(docker volume create --name=sentry-postgres)." -echo "Created $(docker volume create --name=sentry-redis)." -echo "Created $(docker volume create --name=sentry-symbolicator)." +create_volume() { + create_command="$CONTAINER_ENGINE volume create" + if [ "$CONTAINER_ENGINE" = "podman" ]; then + create_command="$create_command --ignore $1" + else + create_command="$create_command --name=$1" + fi + + $create_command +} + +echo "Created $(create_volume sentry-clickhouse)." +echo "Created $(create_volume sentry-data)." +echo "Created $(create_volume sentry-kafka)." +echo "Created $(create_volume sentry-postgres)." +echo "Created $(create_volume sentry-redis)." +echo "Created $(create_volume sentry-symbolicator)." echo "${_endgroup}" diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index 5acaf59c676..6f9d4230d77 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -6,17 +6,27 @@ else _endgroup="" fi -echo "${_group}Initializing Docker Compose ..." +echo "${_group}Initializing Docker|Podman Compose ..." + +export CONTAINER_ENGINE="docker" +if [[ "${CONTAINER_ENGINE_PODMAN:-0}" -eq 1 ]]; then + if command -v podman &>/dev/null; then + export CONTAINER_ENGINE="podman" + else + echo "FAIL: Podman is not installed on the system." + exit 1 + fi +fi # To support users that are symlinking to docker-compose -dc_base="$(docker compose version --short &>/dev/null && echo 'docker compose' || echo '')" -dc_base_standalone="$(docker-compose version --short &>/dev/null && echo 'docker-compose' || echo '')" +dc_base="$(${CONTAINER_ENGINE} compose version --short &>/dev/null && echo "$CONTAINER_ENGINE compose" || echo '')" +dc_base_standalone="$(${CONTAINER_ENGINE}-compose version --short &>/dev/null && echo "$CONTAINER_ENGINE-compose" || echo '')" COMPOSE_VERSION=$([ -n "$dc_base" ] && $dc_base version --short || echo '') STANDALONE_COMPOSE_VERSION=$([ -n "$dc_base_standalone" ] && $dc_base_standalone version --short || echo '') if [[ -z "$COMPOSE_VERSION" && -z "$STANDALONE_COMPOSE_VERSION" ]]; then - echo "FAIL: Docker Compose is required to run self-hosted" + echo "FAIL: Docker|Podman Compose is required to run self-hosted" exit 1 fi @@ -25,14 +35,57 @@ if [[ -z "$COMPOSE_VERSION" ]] || [[ -n "$STANDALONE_COMPOSE_VERSION" ]] && ! ve dc_base="$dc_base_standalone" fi +if [[ "$CONTAINER_ENGINE" == "podman" ]]; then + NO_ANSI="--no-ansi" +else + NO_ANSI="--ansi never" +fi + if [[ "$(basename $0)" = "install.sh" ]]; then - dc="$dc_base --ansi never --env-file ${_ENV}" + dc="$dc_base $NO_ANSI --env-file ${_ENV}" else - dc="$dc_base --ansi never" + dc="$dc_base $NO_ANSI" fi + proxy_args="--build-arg http_proxy=${http_proxy:-} --build-arg https_proxy=${https_proxy:-} --build-arg no_proxy=${no_proxy:-}" -dcr="$dc run --pull=never --rm" +if [[ "$CONTAINER_ENGINE" == "podman" ]]; then + proxy_args_dc="--podman-build-args http_proxy=${http_proxy:-},https_proxy=${https_proxy:-},no_proxy=${no_proxy:-}" + # Disable pod creation as these are one-off commands and creating a pod + # prints its pod id to stdout which is messing with the output that we + # rely on various places such as configuration generation + dcr="$dc --profile=feature-complete --in-pod=false run --rm" +else + proxy_args_dc=$proxy_args + dcr="$dc run --pull=never --rm" +fi dcb="$dc build $proxy_args" -dbuild="docker build $proxy_args" +dbuild="$CONTAINER_ENGINE build $proxy_args" echo "$dcr" +# Utility function to handle --wait with docker and podman +function start_service_and_wait_ready() { + local options=() + local services=() + local found_service=0 + + for arg in "$@"; do + if [[ $found_service -eq 0 && "$arg" == -* ]]; then + options+=("$arg") + else + found_service=1 + services+=("$arg") + fi + done + + if [ "$CONTAINER_ENGINE" = "podman" ]; then + $dc up --force-recreate -d "${options[@]}" "${services[@]}" + for service in "${services[@]}"; do + while ! $CONTAINER_ENGINE ps --filter "health=healthy" | grep "$service"; do + sleep 2 + done + done + else + $dc up --wait "${options[@]}" "${services[@]}" + fi +} + echo "${_endgroup}" diff --git a/install/detect-platform.sh b/install/detect-platform.sh index 7404008f41c..9009f79b63d 100644 --- a/install/detect-platform.sh +++ b/install/detect-platform.sh @@ -1,3 +1,5 @@ +source install/_detect-container-engine.sh + echo "${_group}Detecting Docker platform" # Sentry SaaS uses stock Yandex ClickHouse, but they don't provide images that @@ -12,13 +14,13 @@ echo "${_group}Detecting Docker platform" # linux/amd64 by default due to virtualization. # See https://github.com/docker/cli/issues/3286 for the Docker bug. -if ! command -v docker &>/dev/null; then - echo "FAIL: Could not find a \`docker\` binary on this system. Are you sure it's installed?" - exit 1 +FORMAT="{{.Architecture}}" +if [[ $CONTAINER_ENGINE == "podman" ]]; then + FORMAT="{{.Host.Arch}}" fi -export DOCKER_ARCH=$(docker info --format '{{.Architecture}}') -if [[ "$DOCKER_ARCH" = "x86_64" ]]; then +export DOCKER_ARCH=$($CONTAINER_ENGINE info --format "$FORMAT") +if [[ "$DOCKER_ARCH" = "x86_64" || "$DOCKER_ARCH" = "amd64" ]]; then export DOCKER_PLATFORM="linux/amd64" elif [[ "$DOCKER_ARCH" = "aarch64" ]]; then export DOCKER_PLATFORM="linux/arm64" diff --git a/install/ensure-correct-permissions-profiles-dir.sh b/install/ensure-correct-permissions-profiles-dir.sh index 68b782bc8a5..8c590b3aeba 100755 --- a/install/ensure-correct-permissions-profiles-dir.sh +++ b/install/ensure-correct-permissions-profiles-dir.sh @@ -3,5 +3,7 @@ # TODO: Remove this after the next hard-stop echo "${_group}Ensuring correct permissions on profiles directory ..." + $dcr --no-deps --entrypoint /bin/bash --user root vroom -c 'chown -R vroom:vroom /var/vroom/sentry-profiles && chmod -R o+rwx /var/vroom/sentry-profiles' + echo "${_endgroup}" diff --git a/install/error-handling.sh b/install/error-handling.sh index cbd0676858a..09aa1c2fe13 100644 --- a/install/error-handling.sh +++ b/install/error-handling.sh @@ -6,8 +6,8 @@ fi $dbuild -t sentry-self-hosted-jq-local --platform="$DOCKER_PLATFORM" jq -jq="docker run --rm -i sentry-self-hosted-jq-local" -sentry_cli="docker run --rm -v /tmp:/work -e SENTRY_DSN=$SENTRY_DSN getsentry/sentry-cli" +jq="$CONTAINER_ENGINE run --rm -i sentry-self-hosted-jq-local" +sentry_cli="$CONTAINER_ENGINE run --rm -v /tmp:/work -e SENTRY_DSN=$SENTRY_DSN getsentry/sentry-cli" send_envelope() { # Send envelope @@ -27,7 +27,7 @@ send_event() { local breadcrumbs=$5 local fingerprint_value=$( echo -n "$cmd_exit $error_msg $traceback" | - docker run -i --rm busybox md5sum | + $CONTAINER_ENGINE run -i --rm busybox md5sum | cut -d' ' -f1 ) local envelope_file="sentry-envelope-${fingerprint_value}" @@ -151,7 +151,7 @@ fi # Make sure we can use sentry-cli if we need it. if [ "$REPORT_SELF_HOSTED_ISSUES" == 1 ]; then - if ! docker pull getsentry/sentry-cli:latest; then + if ! $CONTAINER_ENGINE pull getsentry/sentry-cli:latest; then echo "Failed to pull sentry-cli, won't report to Sentry after all." export REPORT_SELF_HOSTED_ISSUES=0 fi diff --git a/install/geoip.sh b/install/geoip.sh index 041db9b6833..0d1b2efc0aa 100644 --- a/install/geoip.sh +++ b/install/geoip.sh @@ -21,7 +21,7 @@ install_geoip() { else echo "IP address geolocation is configured for updates." echo "Updating IP address geolocation database ... " - if ! docker run --rm -v "./geoip:/sentry" --entrypoint '/usr/bin/geoipupdate' "ghcr.io/maxmind/geoipupdate:v6.1.0" "-d" "/sentry" "-f" "/sentry/GeoIP.conf"; then + if ! $CONTAINER_ENGINE run --rm -v "./geoip:/sentry" --entrypoint '/usr/bin/geoipupdate' "ghcr.io/maxmind/geoipupdate:v6.1.0" "-d" "/sentry" "-f" "/sentry/GeoIP.conf"; then result='Error' fi echo "$result updating IP address geolocation database." diff --git a/install/parse-cli.sh b/install/parse-cli.sh index 0390b54f9e9..b342033ca08 100644 --- a/install/parse-cli.sh +++ b/install/parse-cli.sh @@ -4,7 +4,7 @@ show_help() { cat <stdout redirection below and pass it through grep, ignoring all lines -# having this '-onpremise-local' suffix. +if [ "$CONTAINER_ENGINE" = "podman" ]; then + # podman compose doesn't have the --ignore-pull-failures option, so can just + # run the command normally + $dc --profile feature-complete pull || true +else + # We tag locally built images with a '-self-hosted-local' suffix. `docker + # compose pull` tries to pull these too and shows a 404 error on the console + # which is confusing and unnecessary. To overcome this, we add the + # stderr>stdout redirection below and pass it through grep, ignoring all lines + # having this '-onpremise-local' suffix. -$dc pull -q --ignore-pull-failures 2>&1 | grep -v -- -self-hosted-local || true + $dc pull --ignore-pull-failures 2>&1 | grep -v -- -self-hosted-local || true +fi # We may not have the set image on the repo (local images) so allow fails -docker pull ${SENTRY_IMAGE} || true +$CONTAINER_ENGINE pull ${SENTRY_IMAGE} || true echo "${_endgroup}" diff --git a/install/upgrade-clickhouse.sh b/install/upgrade-clickhouse.sh index 3dcb56f189c..93456b8ddbe 100644 --- a/install/upgrade-clickhouse.sh +++ b/install/upgrade-clickhouse.sh @@ -1,19 +1,28 @@ echo "${_group}Upgrading Clickhouse ..." # First check to see if user is upgrading by checking for existing clickhouse volume -if $dc ps -a | grep -q clickhouse; then +if [ "$CONTAINER_ENGINE" = "podman" ]; then + ps_command="$dc ps" + build_arg="--podman-build-args" +else + # docker compose needs to be run with the -a flag to show all containers + ps_command="$dc ps -a" + build_arg="--build-arg" +fi + +if $ps_command | grep -q clickhouse; then # Start clickhouse if it is not already running - $dc up --wait clickhouse + start_service_and_wait_ready clickhouse # In order to get to 23.8, we need to first upgrade go from 21.8 -> 22.8 -> 23.3 -> 23.8 version=$($dc exec clickhouse clickhouse-client -q 'SELECT version()') if [[ "$version" == "21.8.13.1.altinitystable" || "$version" == "21.8.12.29.altinitydev.arm" ]]; then $dc down clickhouse - $dcb --build-arg BASE_IMAGE=altinity/clickhouse-server:22.8.15.25.altinitystable clickhouse - $dc up --wait clickhouse + $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:22.8.15.25.altinitystable clickhouse + start_service_and_wait_ready clickhouse $dc down clickhouse - $dcb --build-arg BASE_IMAGE=altinity/clickhouse-server:23.3.19.33.altinitystable clickhouse - $dc up --wait clickhouse + $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:23.3.19.33.altinitystable clickhouse + start_service_and_wait_ready clickhouse else echo "Detected clickhouse version $version. Skipping upgrades!" fi diff --git a/install/upgrade-postgres.sh b/install/upgrade-postgres.sh index fa66a0aa4ab..6785ae879ea 100644 --- a/install/upgrade-postgres.sh +++ b/install/upgrade-postgres.sh @@ -1,26 +1,26 @@ echo "${_group}Ensuring proper PostgreSQL version ..." -if [[ -n "$(docker volume ls -q --filter name=sentry-postgres)" && "$(docker run --rm -v sentry-postgres:/db busybox cat /db/PG_VERSION 2>/dev/null)" == "9.6" ]]; then - docker volume rm sentry-postgres-new || true +if [[ -n "$($CONTAINER_ENGINE volume ls -q --filter name=sentry-postgres)" && "$($CONTAINER_ENGINE run --rm -v sentry-postgres:/db busybox cat /db/PG_VERSION 2>/dev/null)" == "9.6" ]]; then + $CONTAINER_ENGINE volume rm sentry-postgres-new || true # If this is Postgres 9.6 data, start upgrading it to 14.0 in a new volume - docker run --rm \ + $CONTAINER_ENGINE run --rm \ -v sentry-postgres:/var/lib/postgresql/9.6/data \ -v sentry-postgres-new:/var/lib/postgresql/14/data \ tianon/postgres-upgrade:9.6-to-14 # Get rid of the old volume as we'll rename the new one to that - docker volume rm sentry-postgres - docker volume create --name sentry-postgres + $CONTAINER_ENGINE volume rm sentry-postgres + $CONTAINER_ENGINE volume create --name sentry-postgres # There's no rename volume in Docker so copy the contents from old to new name # Also append the `host all all all trust` line as `tianon/postgres-upgrade:9.6-to-14` # doesn't do that automatically. - docker run --rm -v sentry-postgres-new:/from -v sentry-postgres:/to alpine ash -c \ + $CONTAINER_ENGINE run --rm -v sentry-postgres-new:/from -v sentry-postgres:/to alpine ash -c \ "cd /from ; cp -av . /to ; echo 'host all all all trust' >> /to/pg_hba.conf" # Finally, remove the new old volume as we are all in sentry-postgres now. - docker volume rm sentry-postgres-new + $CONTAINER_ENGINE volume rm sentry-postgres-new echo "Re-indexing due to glibc change, this may take a while..." echo "Starting up new PostgreSQL version" - $dc up --wait postgres + start_service_and_wait_ready postgres # Wait for postgres RETRIES=5 diff --git a/install/wrap-up.sh b/install/wrap-up.sh index 6f242284fe6..52e31137d84 100644 --- a/install/wrap-up.sh +++ b/install/wrap-up.sh @@ -2,15 +2,15 @@ if [[ "$MINIMIZE_DOWNTIME" ]]; then echo "${_group}Waiting for Sentry to start ..." # Start the whole setup, except nginx and relay. - $dc up --wait --remove-orphans $($dc config --services | grep -v -E '^(nginx|relay)$') + start_service_and_wait_ready --remove-orphans $($dc config --services | grep -v -E '^(nginx|relay)$') $dc restart relay $dc exec -T nginx nginx -s reload - docker run --rm --network="${COMPOSE_PROJECT_NAME}_default" alpine ash \ + $CONTAINER_ENGINE run --rm --network="${COMPOSE_PROJECT_NAME}_default" alpine ash \ -c 'while [[ "$(wget -T 1 -q -O- http://web:9000/_health/)" != "ok" ]]; do sleep 0.5; done' # Make sure everything is up. This should only touch relay and nginx - $dc up --wait + start_service_and_wait_ready $($dc config --services) echo "${_endgroup}" else @@ -22,7 +22,15 @@ else if [[ "${_ENV}" =~ ".env.custom" ]]; then echo " $dc_base --env-file .env --env-file ${_ENV} up --wait" else - echo " $dc_base up --wait" + if [[ "$CONTAINER_ENGINE" == "podman" ]]; then + if [[ "$COMPOSE_PROFILES" == "feature-complete" ]]; then + echo " $dc_base --profile=feature-complete up --force-recreate -d" + else + echo " $dc_base up --force-recreate -d" + fi + else + echo " $dc_base up --wait" + fi fi echo "" echo "-----------------------------------------------------------------" diff --git a/sentry-admin.sh b/sentry-admin.sh index f90af33c81a..689e7fab14f 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -23,8 +23,8 @@ on the host filesystem. Commands that write files should write them to the '/sen # Actual invocation that runs the command in the container. invocation() { - $dc up postgres --wait - $dc up redis --wait + start_service_and_wait_ready postgres + start_service_and_wait_ready redis --wait $dcr --no-deps -v "$VOLUME_MAPPING" -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 } From 79f18eeec3f61ac60f6b9a4015b16eaeb165d8a5 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 25 Jul 2025 10:19:52 +0700 Subject: [PATCH 204/305] docs: clearly state that `system.internal-url-prefix` shouldn't be changed (#3829) * docs: clearly state that `system.internal-url-prefix` shouldn't be changed Happened today on Discord where a user changed internal-url-prefix and broke their instance. I think this should be stated clearer for new users and for non-native English speakers. * Apply suggestion from @BYK Co-authored-by: Burak Yigit Kaya * Apply suggestion from @aldy505 Co-authored-by: Reinaldy Rafli * Apply changes from @BYK --------- Co-authored-by: Burak Yigit Kaya --- sentry/config.example.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sentry/config.example.yml b/sentry/config.example.yml index 3c499e7a625..fefe9511b81 100644 --- a/sentry/config.example.yml +++ b/sentry/config.example.yml @@ -45,8 +45,18 @@ mail.host: 'smtp' # System Settings # ################### -# The URL prefix in which Sentry is accessible +# This is the main URL prefix where Sentry can be accessed. +# Sentry will use this to create links to its different parts of the web UI. +# This is most helpful if you are using an external reverse proxy. # system.url-prefix: https://example.sentry.com + +# Most of the time, this should NOT be changed. It's used for communication +# between containers. `web` is the container's name, and `9000` is the +# default port opened by the Sentry backend (this is NOT the public port). +# +# If you want to change the publicly exposed domain or port, you should change +# `system.url-prefix` above instead, along with `SENTRY_BIND` in `.env` file. +# Also see https://develop.sentry.dev/self-hosted/#productionalizing. system.internal-url-prefix: 'http://web:9000' # If this file ever becomes compromised, it's important to generate a new key. From 524b8d4db085f960afe1544c90dda7762cd5f747 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sun, 27 Jul 2025 08:57:01 +0700 Subject: [PATCH 205/305] Potential fix for code scanning alert no. 12: Workflow does not contain permissions (#3822) Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e66f8668330..1ad0a1c4c8b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,3 +1,5 @@ +permissions: + contents: read name: Test on: # Run CI on all pushes to the master and release/** branches, and on all new From 84d0d23af899d90a2adf2451d247f545a1549246 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 29 Jul 2025 17:17:23 +0700 Subject: [PATCH 206/305] feat(features): add `profiling-view` flag (#3837) Closes https://github.com/getsentry/sentry/issues/95752 --- sentry/sentry.conf.example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 0c8bb2b38df..bedb79ff822 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -297,6 +297,7 @@ def get_internal_network(): "organizations:session-replay", "organizations:issue-platform", "organizations:profiling", + "organizations:profiling-view", "organizations:monitors", "organizations:dashboards-mep", "organizations:mep-rollout-flag", From 3f48e35813edf22ae8dee170ea6645900440b117 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 3 Aug 2025 21:07:35 -0400 Subject: [PATCH 207/305] feat: Continue using celery in self-hosted for now (#3845) Disable taskworkers for self-hosted until the documentation has been published. Refs getsentry/sentry#96966 --- sentry/sentry.conf.example.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index bedb79ff822..ee3cc5f93f8 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -442,3 +442,9 @@ def get_internal_network(): # } # SENTRY_METRICS_SAMPLE_RATE = 1.0 # Adjust this to your needs, default is 1.0 # SENTRY_METRICS_PREFIX = "sentry." # Adjust this to your needs, default is "sentry." + +######### +# Tasks # +######### +# Disable taskworker and continue using celery. +SENTRY_OPTIONS["taskworker.enabled"] = False From 29000f157c8563c2263eb902fc165080eadf7a6c Mon Sep 17 00:00:00 2001 From: mzglinski Date: Wed, 6 Aug 2025 00:35:30 +0200 Subject: [PATCH 208/305] fix: add schedulers for generic metrics subscriptions (#3847) --- docker-compose.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 3373402c58a..f29a9bfd56f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -267,6 +267,26 @@ services: command: subscriptions-scheduler-executor --dataset metrics --entity metrics_sets --entity metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-metrics-subscriptions-consumers --followed-consumer-group=snuba-metrics-consumers --schedule-ttl=60 --stale-threshold-seconds=900 profiles: - feature-complete + snuba-subscription-consumer-generic-metrics-distributions: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_distributions --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-distributions-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-distributions-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + profiles: + - feature-complete + snuba-subscription-consumer-generic-metrics-sets: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_sets --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-sets-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-sets-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + profiles: + - feature-complete + snuba-subscription-consumer-generic-metrics-counters: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-counters-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-counters-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + profiles: + - feature-complete + snuba-subscription-consumer-generic-metrics-gauges: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_gauges --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-gauges-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-gauges-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + profiles: + - feature-complete snuba-generic-metrics-distributions-consumer: <<: *snuba_defaults command: rust-consumer --storage generic_metrics_distributions_raw --consumer-group snuba-gen-metrics-distributions-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset From d57613714caf1c5cac77531e20925de8c4a75c01 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 6 Aug 2025 07:05:36 +0700 Subject: [PATCH 209/305] chore(features): cleanup feature flags grouped by its' category (#3843) --- sentry/sentry.conf.example.py | 39 +++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index ee3cc5f93f8..826f43ae2d6 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -279,6 +279,13 @@ def get_internal_network(): # Features # ############ +# Sentry uses feature flags to enable certain features. Some features may +# require additional configuration or containers. To learn more about how +# Sentry uses feature flags, see https://develop.sentry.dev/backend/application-domains/feature-flags/ +# +# The features listed here are stable and generally available on SaaS. +# To enable preview features, see https://develop.sentry.dev/self-hosted/configuration/#enabling-preview-features + SENTRY_FEATURES["projects:sample-events"] = False SENTRY_FEATURES.update( { @@ -292,18 +299,12 @@ def get_internal_network(): "organizations:invite-members", "organizations:sso-basic", "organizations:sso-saml2", - "organizations:performance-view", "organizations:advanced-search", - "organizations:session-replay", "organizations:issue-platform", - "organizations:profiling", - "organizations:profiling-view", "organizations:monitors", "organizations:dashboards-mep", "organizations:mep-rollout-flag", "organizations:dashboards-rh-widget", - "organizations:transaction-metrics-extraction", - "organizations:visibility-explore-view", "organizations:dynamic-sampling", "projects:custom-inbound-filters", "projects:data-forwarding", @@ -312,8 +313,11 @@ def get_internal_network(): "projects:rate-limits", "projects:servicehooks", ) - # Starfish related flags + # Performance/Tracing/Spans related flags + ( + "organizations:performance-view", + "organizations:visibility-explore-view", + "organizations:transaction-metrics-extraction", "organizations:indexed-spans-extraction", "organizations:insights-entry-points", "organizations:insights-initial-modules", @@ -323,33 +327,32 @@ def get_internal_network(): "projects:span-metrics-extraction", "projects:span-metrics-extraction-addons", ) + # Session Replay related flags + + ( + "organizations:session-replay", + ) # User Feedback related flags + ( "organizations:user-feedback-ui", ) + # Profiling related flags + + ( + "organizations:profiling", + "organizations:profiling-view", + ) # Continuous Profiling related flags + ( "organizations:continuous-profiling", "organizations:continuous-profiling-stats", ) - # Uptime related flags + # Uptime Monitoring related flags + ( "organizations:uptime", "organizations:uptime-create-issues", - # TODO(epurkhiser): We can remove remove these in 25.8.0 since - # we'll have released this issue group type - # (https://github.com/getsentry/sentry/pull/94827) - "organizations:issue-uptime-domain-failure-visible", - "organizations:issue-uptime-domain-failure-ingest", - "organizations:issue-uptime-domain-failure-post-process-group", ) } ) -# TODO(epurkhiser): In 25.8.0 we can drop this option override as we've made it -# default in sentry (https://github.com/getsentry/sentry/pull/94822) -SENTRY_OPTIONS["uptime.snuba_uptime_results.enabled"] = True - ####################### # MaxMind Integration # ####################### From a36deff0af00f3b895120ed294ffdea8f23e1ccf Mon Sep 17 00:00:00 2001 From: Iven Schlenther Date: Wed, 6 Aug 2025 11:44:23 +0200 Subject: [PATCH 210/305] fix(enhancement): ensure correct ownership check before setting permissions of profiles (#3855) --- install/ensure-correct-permissions-profiles-dir.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/install/ensure-correct-permissions-profiles-dir.sh b/install/ensure-correct-permissions-profiles-dir.sh index 8c590b3aeba..9f784c86b2b 100755 --- a/install/ensure-correct-permissions-profiles-dir.sh +++ b/install/ensure-correct-permissions-profiles-dir.sh @@ -4,6 +4,11 @@ echo "${_group}Ensuring correct permissions on profiles directory ..." -$dcr --no-deps --entrypoint /bin/bash --user root vroom -c 'chown -R vroom:vroom /var/vroom/sentry-profiles && chmod -R o+rwx /var/vroom/sentry-profiles' +# Check if the parent directory of /var/vroom/sentry-profiles is already owned by vroom:vroom +if [ "$(stat -c '%U:%G' /var/vroom)" = "vroom:vroom" ]; then + echo "Ownership of /var/vroom is already set to vroom:vroom. Skipping chown." +else + $dcr --no-deps --entrypoint /bin/bash --user root vroom -c 'chown -R vroom:vroom /var/vroom/sentry-profiles && chmod -R o+rwx /var/vroom/sentry-profiles' +fi echo "${_endgroup}" From abe68ba370d8b9e1b3f0ea5bbc181044ae78be23 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 6 Aug 2025 22:56:47 +0700 Subject: [PATCH 211/305] fix: uptime checker image should be bumped to the tagged release (#3858) --- scripts/bump-version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index f5853a3e2f4..df69deb71a0 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -4,7 +4,7 @@ set -eu OLD_VERSION="$1" NEW_VERSION="$2" -sed -i -e "s/^\(SENTRY\|SNUBA\|RELAY\|SYMBOLICATOR\|TASKBROKER\|VROOM\)_IMAGE=\([^:]\+\):.\+\$/\1_IMAGE=\2:$NEW_VERSION/" .env +sed -i -e "s/^\(SENTRY\|SNUBA\|RELAY\|SYMBOLICATOR\|TASKBROKER\|VROOM\|UPTIME_CHECKER\)_IMAGE=\([^:]\+\):.\+\$/\1_IMAGE=\2:$NEW_VERSION/" .env sed -i -e "s/^\# Self-Hosted Sentry .*/# Self-Hosted Sentry $NEW_VERSION/" README.md [ -z "$OLD_VERSION" ] || echo "Previous version: $OLD_VERSION" From 213423f9d9465a3a679cf20a6c06229a17af7dbd Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 7 Aug 2025 10:14:02 +0700 Subject: [PATCH 212/305] fix(scripts): every known flags should be shifted before executing the sentry command (#3831) Fixes https://github.com/getsentry/self-hosted/issues/3526 Previously, if this was executed: ```bash ./scripts/backup.sh --no-report-self-hosted-issues ``` The final backup command that will be executed is: ```bash docker compose run -v "${PWD}/sentry:/sentry-data/backup" --rm -T -e SENTRY_LOG_LEVEL=CRITICAL web export --no-report-self-hosted-issues /sentry-data/backup/backup.json ``` Which is invalid. This PR strips all known flags specific to self-hosted before passing it onto Sentry. One other option is to enable "ignore unknown options" on click (the CLI dependency) on Sentry, but I don't want to go to that route. --- scripts/_lib.sh | 11 +---------- scripts/backup.sh | 13 +++++++++++++ scripts/reset.sh | 13 +++++++++++++ scripts/restore.sh | 13 +++++++++++++ 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/scripts/_lib.sh b/scripts/_lib.sh index ba57fc42a33..a381b6e585d 100755 --- a/scripts/_lib.sh +++ b/scripts/_lib.sh @@ -78,7 +78,6 @@ function restore() { } # Needed variables to source error-handling script -MINIMIZE_DOWNTIME="${MINIMIZE_DOWNTIME:-}" export STOP_TIMEOUT=60 # Save logs in order to send envelope to Sentry @@ -86,16 +85,8 @@ log_file="sentry_${cmd%% *}_log-$(date +%Y-%m-%d_%H-%M-%S).txt" exec &> >(tee -a "$log_file") version="" -while (($#)); do - case "$1" in - --report-self-hosted-issues) export REPORT_SELF_HOSTED_ISSUES=1 ;; - --no-report-self-hosted-issues) export REPORT_SELF_HOSTED_ISSUES=0 ;; - *) version=$1 ;; - esac - shift -done - # Source files needed to set up error-handling +source install/_lib.sh source install/dc-detect-version.sh source install/detect-platform.sh source install/error-handling.sh diff --git a/scripts/backup.sh b/scripts/backup.sh index c056b7078bc..c92ee4b9ace 100755 --- a/scripts/backup.sh +++ b/scripts/backup.sh @@ -1,4 +1,17 @@ #!/usr/bin/env bash +MINIMIZE_DOWNTIME="${MINIMIZE_DOWNTIME:-}" +REPORT_SELF_HOSTED_ISSUES="${REPORT_SELF_HOSTED_ISSUES:-}" + +while (($#)); do + case "$1" in + --report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=1 ;; + --no-report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=0 ;; + --minimize-downtime) MINIMIZE_DOWNTIME=1 ;; + *) version=$1 ;; + esac + shift +done + cmd="backup $1" source scripts/_lib.sh $cmd diff --git a/scripts/reset.sh b/scripts/reset.sh index f519435420f..75c244efedc 100755 --- a/scripts/reset.sh +++ b/scripts/reset.sh @@ -1,4 +1,17 @@ #!/usr/bin/env bash +MINIMIZE_DOWNTIME="${MINIMIZE_DOWNTIME:-}" +REPORT_SELF_HOSTED_ISSUES="${REPORT_SELF_HOSTED_ISSUES:-}" + +while (($#)); do + case "$1" in + --report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=1 ;; + --no-report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=0 ;; + --minimize-downtime) MINIMIZE_DOWNTIME=1 ;; + *) version=$1 ;; + esac + shift +done + cmd=reset source scripts/_lib.sh $cmd diff --git a/scripts/restore.sh b/scripts/restore.sh index ae3666b0ec6..57cab1bb60c 100755 --- a/scripts/restore.sh +++ b/scripts/restore.sh @@ -1,4 +1,17 @@ #!/usr/bin/env bash +MINIMIZE_DOWNTIME="${MINIMIZE_DOWNTIME:-}" +REPORT_SELF_HOSTED_ISSUES="${REPORT_SELF_HOSTED_ISSUES:-}" + +while (($#)); do + case "$1" in + --report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=1 ;; + --no-report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=0 ;; + --minimize-downtime) MINIMIZE_DOWNTIME=1 ;; + *) version=$1 ;; + esac + shift +done + cmd="restore $1" source scripts/_lib.sh From 2b549baee767c2dd7b0f3ccd3caf2bf1c073cfc3 Mon Sep 17 00:00:00 2001 From: Kamil Monicz Date: Sun, 10 Aug 2025 02:48:47 +0200 Subject: [PATCH 213/305] fix(scripts): use `env` to find `bash` interpreter (#3861) --- install/ensure-correct-permissions-profiles-dir.sh | 2 +- scripts/bump-version.sh | 2 +- scripts/post-release.sh | 2 +- sentry-admin.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/install/ensure-correct-permissions-profiles-dir.sh b/install/ensure-correct-permissions-profiles-dir.sh index 9f784c86b2b..5bdadecc70c 100755 --- a/install/ensure-correct-permissions-profiles-dir.sh +++ b/install/ensure-correct-permissions-profiles-dir.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # TODO: Remove this after the next hard-stop diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index df69deb71a0..64ff9732bf9 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -eu OLD_VERSION="$1" diff --git a/scripts/post-release.sh b/scripts/post-release.sh index 820d8ef6d69..f2e6a238d16 100755 --- a/scripts/post-release.sh +++ b/scripts/post-release.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -eu # Bring master back to nightlies after merge from release branch diff --git a/sentry-admin.sh b/sentry-admin.sh index 689e7fab14f..aeea2b36845 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Set the script directory as working directory. cd $(dirname $0) From d3c0ea8250de4b987ab6f9dc09177a069da247d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:38:01 +0100 Subject: [PATCH 214/305] build(deps): bump actions/create-github-app-token from 2.0.6 to 2.1.0 (#3865) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.0.6 to 2.1.0. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/df432ceedc7162793a195dd1713ff69aefc7379e...0f859bf9e69e887678d5bbfbee594437cb440ffe) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 2.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d744f50290a..87699d3b48d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + uses: actions/create-github-app-token@0f859bf9e69e887678d5bbfbee594437cb440ffe # v2.1.0 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From 8bf5663c0a11e10a5e63fab376106a3af4f79691 Mon Sep 17 00:00:00 2001 From: Pierre Massat Date: Tue, 12 Aug 2025 12:48:43 -0700 Subject: [PATCH 215/305] fix(eap): Fix dataset parameter to target spans (#3866) --- _integration-test/test_01_basics.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/_integration-test/test_01_basics.py b/_integration-test/test_01_basics.py index 14ffa253067..b759f629730 100644 --- a/_integration-test/test_01_basics.py +++ b/_integration-test/test_01_basics.py @@ -180,7 +180,9 @@ def test_custom_certificate_authorities(): .public_key(ca_key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.datetime.now(datetime.timezone.utc)) - .not_valid_after(datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1)) + .not_valid_after( + datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1) + ) .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True) .add_extension( x509.KeyUsage( @@ -398,7 +400,7 @@ def placeholder_fn(): lambda x: len(json.loads(x)["data"]) > 0, ) poll_for_response( - f"{SENTRY_TEST_HOST}/api/0/organizations/sentry/events/?dataset=spansIndexed&field=id&project=1&statsPeriod=1h", + f"{SENTRY_TEST_HOST}/api/0/organizations/sentry/events/?dataset=spans&field=id&project=1&statsPeriod=1h", client, lambda x: len(json.loads(x)["data"]) > 0, ) From 43d4c5df0e036ffa417ce2087fe37abbe20a09e7 Mon Sep 17 00:00:00 2001 From: mzglinski Date: Wed, 13 Aug 2025 05:51:56 +0200 Subject: [PATCH 216/305] feat: healthchecks for sentry components (#3859) * feat: add snuba healthcheck * fix: snuba healthchecks * fix: remove healthcheck from replacer * feat: add healthchecks to sentry * fix: small changes to sentry healthchecks * fix: worker healthcheck * feat: vroom healthcheck * feat: symbolicator healthcheck * feat: add nginx healthcheck * fix: typo in .env * fix: typo in docker-compose.yml * test: increase docker compose --wait-timeout * Revert "test: increase docker compose --wait-timeout" This reverts commit fc43389793017f8041fc1cdae0a5cb5e2fb759f2. * fix: do not use healthcheck: [disabled: true], since it breaks docker compose wait command --------- Co-authored-by: Reinaldy Rafli --- .env | 5 + docker-compose.yml | 246 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 200 insertions(+), 51 deletions(-) diff --git a/.env b/.env index ee11f6bd67a..6570bf8c28f 100644 --- a/.env +++ b/.env @@ -19,6 +19,11 @@ UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 +HEALTHCHECK_START_PERIOD=10s +HEALTHCHECK_FILE_INTERVAL=60s +HEALTHCHECK_FILE_TIMEOUT=10s +HEALTHCHECK_FILE_RETRIES=1 +HEALTHCHECK_FILE_START_PERIOD=180s # Caution: Raising max connections of postgres increases CPU and RAM usage # see https://github.com/getsentry/self-hosted/pull/2740 for more information POSTGRES_MAX_CONNECTIONS=100 diff --git a/docker-compose.yml b/docker-compose.yml index f29a9bfd56f..437bdc7694c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,13 @@ x-healthcheck-defaults: &healthcheck_defaults interval: "$HEALTHCHECK_INTERVAL" timeout: "$HEALTHCHECK_TIMEOUT" retries: $HEALTHCHECK_RETRIES - start_period: 10s + start_period: "$HEALTHCHECK_START_PERIOD" +x-file-healthcheck: &file_healthcheck_defaults + test: ["CMD-SHELL", "rm /tmp/health.txt"] + interval: "$HEALTHCHECK_FILE_INTERVAL" + timeout: "$HEALTHCHECK_FILE_TIMEOUT" + retries: $HEALTHCHECK_FILE_RETRIES + start_period: "$HEALTHCHECK_FILE_START_PERIOD" x-sentry-defaults: &sentry_defaults <<: [*restart_policy, *pull_policy] image: sentry-self-hosted-local @@ -211,133 +217,193 @@ services: retries: 30 snuba-api: <<: *snuba_defaults + healthcheck: + <<: *healthcheck_defaults + test: + - "CMD" + - "/bin/bash" + - "-c" + # Courtesy of https://unix.stackexchange.com/a/234089/108960 + - 'exec 3<>/dev/tcp/127.0.0.1/1218 && echo -e "GET /health HTTP/1.1\r\nhost: 127.0.0.1\r\n\r\n" >&3 && grep ok -s -m 1 <&3' # Kafka consumer responsible for feeding events into Clickhouse snuba-errors-consumer: <<: *snuba_defaults - command: rust-consumer --storage errors --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage errors --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults # Kafka consumer responsible for feeding outcomes into Clickhouse # Use --auto-offset-reset=earliest to recover up to 7 days of TSDB data # since we did not do a proper migration snuba-outcomes-consumer: <<: *snuba_defaults - command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults snuba-outcomes-billing-consumer: <<: *snuba_defaults - command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset --raw-events-topic outcomes-billing + command: rust-consumer --storage outcomes_raw --consumer-group snuba-consumers --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset --raw-events-topic outcomes-billing --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults snuba-group-attributes-consumer: <<: *snuba_defaults - command: rust-consumer --storage group_attributes --consumer-group snuba-group-attributes-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage group_attributes --consumer-group snuba-group-attributes-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults snuba-replacer: <<: *snuba_defaults command: replacer --storage errors --auto-offset-reset=latest --no-strict-offset-reset snuba-subscription-consumer-events: <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset events --entity events --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-events-subscriptions-consumers --followed-consumer-group=snuba-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + command: subscriptions-scheduler-executor --dataset events --entity events --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-events-subscriptions-consumers --followed-consumer-group=snuba-consumers --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults ############################################# ## Feature Complete Sentry Snuba Consumers ## ############################################# # Kafka consumer responsible for feeding transactions data into Clickhouse snuba-transactions-consumer: <<: *snuba_defaults - command: rust-consumer --storage transactions --consumer-group transactions_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage transactions --consumer-group transactions_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-replays-consumer: <<: *snuba_defaults - command: rust-consumer --storage replays --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage replays --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-issue-occurrence-consumer: <<: *snuba_defaults - command: rust-consumer --storage search_issues --consumer-group generic_events_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage search_issues --consumer-group generic_events_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-metrics-consumer: <<: *snuba_defaults - command: rust-consumer --storage metrics_raw --consumer-group snuba-metrics-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage metrics_raw --consumer-group snuba-metrics-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-subscription-consumer-transactions: <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset transactions --entity transactions --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-transactions-subscriptions-consumers --followed-consumer-group=transactions_group --schedule-ttl=60 --stale-threshold-seconds=900 + command: subscriptions-scheduler-executor --dataset transactions --entity transactions --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-transactions-subscriptions-consumers --followed-consumer-group=transactions_group --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-subscription-consumer-metrics: <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset metrics --entity metrics_sets --entity metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-metrics-subscriptions-consumers --followed-consumer-group=snuba-metrics-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + command: subscriptions-scheduler-executor --dataset metrics --entity metrics_sets --entity metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-metrics-subscriptions-consumers --followed-consumer-group=snuba-metrics-consumers --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-subscription-consumer-generic-metrics-distributions: <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_distributions --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-distributions-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-distributions-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_distributions --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-distributions-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-distributions-consumers --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-subscription-consumer-generic-metrics-sets: <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_sets --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-sets-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-sets-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_sets --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-sets-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-sets-consumers --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-subscription-consumer-generic-metrics-counters: <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-counters-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-counters-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-counters-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-counters-consumers --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-subscription-consumer-generic-metrics-gauges: <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_gauges --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-gauges-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-gauges-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + command: subscriptions-scheduler-executor --dataset generic_metrics --entity=generic_metrics_gauges --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-generic-metrics-gauges-subscriptions-schedulers --followed-consumer-group=snuba-gen-metrics-gauges-consumers --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-generic-metrics-distributions-consumer: <<: *snuba_defaults - command: rust-consumer --storage generic_metrics_distributions_raw --consumer-group snuba-gen-metrics-distributions-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage generic_metrics_distributions_raw --consumer-group snuba-gen-metrics-distributions-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-generic-metrics-sets-consumer: <<: *snuba_defaults - command: rust-consumer --storage generic_metrics_sets_raw --consumer-group snuba-gen-metrics-sets-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage generic_metrics_sets_raw --consumer-group snuba-gen-metrics-sets-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-generic-metrics-counters-consumer: <<: *snuba_defaults - command: rust-consumer --storage generic_metrics_counters_raw --consumer-group snuba-gen-metrics-counters-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage generic_metrics_counters_raw --consumer-group snuba-gen-metrics-counters-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-generic-metrics-gauges-consumer: <<: *snuba_defaults - command: rust-consumer --storage generic_metrics_gauges_raw --consumer-group snuba-gen-metrics-gauges-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage generic_metrics_gauges_raw --consumer-group snuba-gen-metrics-gauges-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-profiling-profiles-consumer: <<: *snuba_defaults - command: rust-consumer --storage profiles --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + command: rust-consumer --storage profiles --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-profiling-functions-consumer: <<: *snuba_defaults - command: rust-consumer --storage functions_raw --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + command: rust-consumer --storage functions_raw --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-profiling-profile-chunks-consumer: <<: *snuba_defaults - command: rust-consumer --storage profile_chunks --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + command: rust-consumer --storage profile_chunks --consumer-group snuba-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-spans-consumer: <<: *snuba_defaults - command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-eap-items-consumer: <<: *snuba_defaults - command: rust-consumer --storage eap_items --consumer-group eap_items_group --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --use-rust-processor + command: rust-consumer --storage eap_items --consumer-group eap_items_group --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --use-rust-processor --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete snuba-subscription-consumer-eap-items: <<: *snuba_defaults - command: subscriptions-scheduler-executor --dataset events_analytics_platform --entity eap_items --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-eap-items-subscriptions-consumers --followed-consumer-group=eap_items_group --schedule-ttl=60 --stale-threshold-seconds=900 + command: subscriptions-scheduler-executor --dataset events_analytics_platform --entity eap_items --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-eap-items-subscriptions-consumers --followed-consumer-group=eap_items_group --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults snuba-uptime-results-consumer: <<: *snuba_defaults - command: rust-consumer --storage uptime_monitor_checks --consumer-group snuba-uptime-results --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + command: rust-consumer --storage uptime_monitor_checks --consumer-group snuba-uptime-results --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete symbolicator: @@ -349,6 +415,14 @@ services: read_only: true source: ./symbolicator target: /etc/symbolicator + healthcheck: + <<: *healthcheck_defaults + test: + - "CMD" + - "/bin/bash" + - "-c" + # Courtesy of https://unix.stackexchange.com/a/234089/108960 + - 'exec 3<>/dev/tcp/127.0.0.1/3021 && echo -e "GET /healthcheck HTTP/1.1\r\nhost: 127.0.0.1\r\nConnection: close\r\n\r\n" >&3 && grep OK -s -m 1 <&3' command: run -c /etc/symbolicator/config.yml symbolicator-cleanup: <<: [*restart_policy, *pull_policy] @@ -380,119 +454,175 @@ services: worker: <<: *sentry_defaults command: run worker + healthcheck: + <<: *healthcheck_defaults + test: + - CMD + - sentry + - exec + - -c + - 'from sentry.celery import app; import os; dest="celery@{}".format(os.environ["HOSTNAME"]); print(app.control.ping(destination=[dest], timeout=5)[0][dest]["ok"])' events-consumer: <<: *sentry_defaults - command: run consumer ingest-events --consumer-group ingest-consumer + command: run consumer ingest-events --consumer-group ingest-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults attachments-consumer: <<: *sentry_defaults - command: run consumer ingest-attachments --consumer-group ingest-consumer + command: run consumer ingest-attachments --consumer-group ingest-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults post-process-forwarder-errors: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset post-process-forwarder-errors --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-commit-log --synchronize-commit-group=snuba-consumers + command: run consumer --no-strict-offset-reset post-process-forwarder-errors --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-commit-log --synchronize-commit-group=snuba-consumers --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults subscription-consumer-events: <<: *sentry_defaults - command: run consumer events-subscription-results --consumer-group query-subscription-consumer + command: run consumer events-subscription-results --consumer-group query-subscription-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults ############################################## ## Feature Complete Sentry Ingest Consumers ## ############################################## transactions-consumer: <<: *sentry_defaults - command: run consumer ingest-transactions --consumer-group ingest-consumer + command: run consumer ingest-transactions --consumer-group ingest-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete metrics-consumer: <<: *sentry_defaults - command: run consumer ingest-metrics --consumer-group metrics-consumer + command: run consumer ingest-metrics --consumer-group metrics-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete generic-metrics-consumer: <<: *sentry_defaults - command: run consumer ingest-generic-metrics --consumer-group generic-metrics-consumer + command: run consumer ingest-generic-metrics --consumer-group generic-metrics-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete billing-metrics-consumer: <<: *sentry_defaults - command: run consumer billing-metrics-consumer --consumer-group billing-metrics-consumer + command: run consumer billing-metrics-consumer --consumer-group billing-metrics-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete ingest-replay-recordings: <<: *sentry_defaults - command: run consumer ingest-replay-recordings --consumer-group ingest-replay-recordings + command: run consumer ingest-replay-recordings --consumer-group ingest-replay-recordings --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete ingest-occurrences: <<: *sentry_defaults - command: run consumer ingest-occurrences --consumer-group ingest-occurrences + command: run consumer ingest-occurrences --consumer-group ingest-occurrences --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete ingest-profiles: <<: *sentry_defaults - command: run consumer ingest-profiles --consumer-group ingest-profiles + command: run consumer ingest-profiles --consumer-group ingest-profiles --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete ingest-monitors: <<: *sentry_defaults - command: run consumer ingest-monitors --consumer-group ingest-monitors + command: run consumer ingest-monitors --consumer-group ingest-monitors --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete ingest-feedback-events: <<: *sentry_defaults - command: run consumer ingest-feedback-events --consumer-group ingest-feedback + command: run consumer ingest-feedback-events --consumer-group ingest-feedback --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete process-spans: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset process-spans --consumer-group process-spans + command: run consumer --no-strict-offset-reset process-spans --consumer-group process-spans --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete process-segments: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset process-segments --consumer-group process-segments + command: run consumer --no-strict-offset-reset process-segments --consumer-group process-segments --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete monitors-clock-tick: <<: *sentry_defaults - command: run consumer monitors-clock-tick --consumer-group monitors-clock-tick + command: run consumer monitors-clock-tick --consumer-group monitors-clock-tick --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete monitors-clock-tasks: <<: *sentry_defaults - command: run consumer monitors-clock-tasks --consumer-group monitors-clock-tasks + command: run consumer monitors-clock-tasks --consumer-group monitors-clock-tasks --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete uptime-results: <<: *sentry_defaults - command: run consumer uptime-results --consumer-group uptime-results + command: run consumer uptime-results --consumer-group uptime-results --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete post-process-forwarder-transactions: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset post-process-forwarder-transactions --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-transactions-commit-log --synchronize-commit-group transactions_group + command: run consumer --no-strict-offset-reset post-process-forwarder-transactions --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-transactions-commit-log --synchronize-commit-group transactions_group --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete post-process-forwarder-issue-platform: <<: *sentry_defaults - command: run consumer --no-strict-offset-reset post-process-forwarder-issue-platform --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-generic-events-commit-log --synchronize-commit-group generic_events_group + command: run consumer --no-strict-offset-reset post-process-forwarder-issue-platform --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-generic-events-commit-log --synchronize-commit-group generic_events_group --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete subscription-consumer-transactions: <<: *sentry_defaults - command: run consumer transactions-subscription-results --consumer-group query-subscription-consumer + command: run consumer transactions-subscription-results --consumer-group query-subscription-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete subscription-consumer-eap-items: <<: *sentry_defaults - command: run consumer subscription-results-eap-items --consumer-group subscription-results-eap-items + command: run consumer subscription-results-eap-items --consumer-group subscription-results-eap-items --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete subscription-consumer-metrics: <<: *sentry_defaults - command: run consumer metrics-subscription-results --consumer-group query-subscription-consumer + command: run consumer metrics-subscription-results --consumer-group query-subscription-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete subscription-consumer-generic-metrics: <<: *sentry_defaults - command: run consumer generic-metrics-subscription-results --consumer-group query-subscription-consumer + command: run consumer generic-metrics-subscription-results --consumer-group query-subscription-consumer --healthcheck-file-path /tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults profiles: - feature-complete sentry-cleanup: @@ -516,6 +646,12 @@ services: target: /etc/nginx/nginx.conf - sentry-nginx-cache:/var/cache/nginx - sentry-nginx-www:/var/www + healthcheck: + <<: *healthcheck_defaults + test: + - "CMD" + - "/usr/bin/curl" + - http://localhost depends_on: - web - relay @@ -566,6 +702,14 @@ services: SENTRY_SNUBA_HOST: "http://snuba-api:1218" volumes: - sentry-vroom:/var/vroom/sentry-profiles + healthcheck: + <<: *healthcheck_defaults + test: + - "CMD" + - "/bin/bash" + - "-c" + # Courtesy of https://unix.stackexchange.com/a/234089/108960 + - 'exec 3<>/dev/tcp/127.0.0.1/8085 && echo -e "GET /health HTTP/1.1\r\nhost: 127.0.0.1\r\n\r\n" >&3 && grep OK -s -m 1 <&3' depends_on: kafka: <<: *depends_on-healthy From 4666d443c7779474dfc29ef7cd19e99755c972ce Mon Sep 17 00:00:00 2001 From: mzglinski Date: Thu, 14 Aug 2025 13:29:46 +0200 Subject: [PATCH 217/305] fix: adjust file healthcheck durations (#3874) --- .env | 4 ++-- action.yaml | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 6570bf8c28f..ba8cf6267b7 100644 --- a/.env +++ b/.env @@ -22,8 +22,8 @@ HEALTHCHECK_RETRIES=10 HEALTHCHECK_START_PERIOD=10s HEALTHCHECK_FILE_INTERVAL=60s HEALTHCHECK_FILE_TIMEOUT=10s -HEALTHCHECK_FILE_RETRIES=1 -HEALTHCHECK_FILE_START_PERIOD=180s +HEALTHCHECK_FILE_RETRIES=3 +HEALTHCHECK_FILE_START_PERIOD=600s # Caution: Raising max connections of postgres increases CPU and RAM usage # see https://github.com/getsentry/self-hosted/pull/2740 for more information POSTGRES_MAX_CONNECTIONS=100 diff --git a/action.yaml b/action.yaml index 40b76283268..99ade7523da 100644 --- a/action.yaml +++ b/action.yaml @@ -142,6 +142,17 @@ runs: volumes: | sentry-kafka + - name: Setup swapfile + shell: bash + if: matrix.os == 'ubuntu-24.04' + run: | + sudo fallocate -l 16G /swapfile + sudo chmod 600 /swapfile + sudo mkswap /swapfile + sudo swapon /swapfile + sudo swapon --show + free -h + - name: Integration Test shell: bash run: | From 0f606d28b86876f91865ac78d52a908e3c623c05 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Thu, 14 Aug 2025 15:11:49 +0330 Subject: [PATCH 218/305] Set minimum bash version to 4.4.0 (#3873) --- install/_min-requirements.sh | 2 ++ install/check-minimum-requirements.sh | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/install/_min-requirements.sh b/install/_min-requirements.sh index 36c5dc0f625..2ffded50700 100644 --- a/install/_min-requirements.sh +++ b/install/_min-requirements.sh @@ -5,6 +5,8 @@ MIN_COMPOSE_VERSION='2.32.2' MIN_PODMAN_VERSION='4.9.3' MIN_PODMAN_COMPOSE_VERSION='1.3.0' +MIN_BASH_VERSION='4.4.0' + # 16 GB minimum host RAM, but there'll be some overhead outside of what # can be allotted to docker if [[ "$COMPOSE_PROFILES" == "errors-only" ]]; then diff --git a/install/check-minimum-requirements.sh b/install/check-minimum-requirements.sh index 322de339759..91e5116b6d3 100644 --- a/install/check-minimum-requirements.sh +++ b/install/check-minimum-requirements.sh @@ -54,4 +54,9 @@ if [[ ! "$SKIP_SSE42_REQUIREMENTS" -eq 1 && "$IS_KVM" -eq 0 && "$DOCKER_ARCH" = fi fi +if ! vergte "${BASH_VERSION}" "${MIN_BASH_VERSION}"; then + echo "FAIL: Expected minimum bash version to be ${MIN_BASH_VERSION} but found ${BASH_VERSION}" + exit 1 +fi + echo "${_endgroup}" From 3614389d887adfe788c51f8935ccda324d4041a1 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 14 Aug 2025 22:09:55 +0700 Subject: [PATCH 219/305] fix: setup swapfile only if runner architecture is X64 or X86 (#3876) Using matrix.os only works on self-hosted. SH e2e test on other repositories would still fail. Refer to https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#runner-context --- action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 99ade7523da..0a655e53bd5 100644 --- a/action.yaml +++ b/action.yaml @@ -144,7 +144,7 @@ runs: - name: Setup swapfile shell: bash - if: matrix.os == 'ubuntu-24.04' + if: runner.arch == 'X64' || runner.arch == 'X86' run: | sudo fallocate -l 16G /swapfile sudo chmod 600 /swapfile From e4d311bb5db4a8fdf0ba4f57eab5e184a534a170 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 14 Aug 2025 22:26:18 +0700 Subject: [PATCH 220/305] feat: Relay healthcheck (#3875) --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 437bdc7694c..8873990cb3e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -674,6 +674,9 @@ services: <<: *depends_on-healthy web: <<: *depends_on-healthy + healthcheck: + <<: *healthcheck_defaults + test: ["CMD", "/bin/relay", "healthcheck"] taskbroker: <<: *restart_policy image: "$TASKBROKER_IMAGE" From f7acf12d764200b65956c2f2e35d478242f88e0b Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Fri, 15 Aug 2025 18:07:35 +0000 Subject: [PATCH 221/305] release: 25.8.0 --- .env | 14 +++++++------- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/.env b/.env index ba8cf6267b7..87fed26356f 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly -SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly -RELAY_IMAGE=ghcr.io/getsentry/relay:nightly -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly -VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.8.0 +SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.8.0 +RELAY_IMAGE=ghcr.io/getsentry/relay:25.8.0 +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.8.0 +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.8.0 +VROOM_IMAGE=ghcr.io/getsentry/vroom:25.8.0 +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.8.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index ea0deec5a96..88a8d4528f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## 25.8.0 + +### Various fixes & improvements + +- feat: Relay healthcheck (#3875) by @aldy505 +- fix: setup swapfile only if runner architecture is X64 or X86 (#3876) by @aldy505 +- Set minimum bash version to 4.4.0 (#3873) by @aminvakil +- fix: adjust file healthcheck durations (#3874) by @mzglinski +- feat: healthchecks for sentry components (#3859) by @mzglinski +- fix(eap): Fix dataset parameter to target spans (#3866) by @phacops +- build(deps): bump actions/create-github-app-token from 2.0.6 to 2.1.0 (#3865) by @dependabot +- fix(scripts): use `env` to find `bash` interpreter (#3861) by @Zaczero +- fix(scripts): every known flags should be shifted before executing the sentry command (#3831) by @aldy505 +- fix: uptime checker image should be bumped to the tagged release (#3858) by @aldy505 +- fix(enhancement): ensure correct ownership check before setting permissions of profiles (#3855) by @LvckyAPI +- chore(features): cleanup feature flags grouped by its' category (#3843) by @aldy505 +- fix: add schedulers for generic metrics subscriptions (#3847) by @mzglinski +- feat: Continue using celery in self-hosted for now (#3845) by @markstory +- feat(features): add `profiling-view` flag (#3837) by @aldy505 +- Potential fix for code scanning alert no. 12: Workflow does not contain permissions (#3822) by @aldy505 +- docs: clearly state that `system.internal-url-prefix` shouldn't be changed (#3829) by @aldy505 +- feat(install): Adds support for podman(compose) (#3673) by @DuncanConroy +- fix(action): missing project directory path for failure inspection (#3825) by @aldy505 +- Cleanup unused feature flags (#3820) by @doc-sheet +- feat: inspect docker compose failure on self-hosted e2e action (#3817) by @aldy505 + ## 25.7.0 ### Various fixes & improvements From 17e638f8f049b10c4eff32ae8fc51ab0c9d1e7d1 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Fri, 15 Aug 2025 20:03:08 +0000 Subject: [PATCH 222/305] build: Set master version to nightly #skip-changelog --- .env | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env b/.env index 87fed26356f..ba8cf6267b7 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.8.0 -SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.8.0 -RELAY_IMAGE=ghcr.io/getsentry/relay:25.8.0 -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.8.0 -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.8.0 -VROOM_IMAGE=ghcr.io/getsentry/vroom:25.8.0 -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.8.0 +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From dc5ac0792db9697f525b80604c6547ef8c313ceb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 19:02:54 +0100 Subject: [PATCH 223/305] build(deps): bump actions/checkout from 4 to 5 (#3883) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/fast-revert.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/shellcheck.yml | 2 +- .github/workflows/test.yml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/fast-revert.yml b/.github/workflows/fast-revert.yml index d3699da4609..6b88ed831a5 100644 --- a/.github/workflows/fast-revert.yml +++ b/.github/workflows/fast-revert.yml @@ -19,7 +19,7 @@ jobs: if: | github.event_name == 'workflow_dispatch' || github.event.label.name == 'Trigger: Revert' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: token: ${{ secrets.BUMP_SENTRY_TOKEN }} - uses: getsentry/action-fast-revert@v2.0.1 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index f8169727aff..6a449b9da7c 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -9,7 +9,7 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-python@v5 with: python-version: 3.x diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 87699d3b48d..c7d447e130a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: token: ${{ steps.token.outputs.token }} fetch-depth: 0 @@ -46,7 +46,7 @@ jobs: name: Create release on self-hosted dogfood instance needs: release steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 - uses: getsentry/action-release@v3 diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index c5cc25e8cbb..889817caaf8 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Repository checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1ad0a1c4c8b..99448af00c3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,7 +30,7 @@ jobs: name: ${{ matrix.os == 'ubuntu-24.04-arm' && 'unit tests (arm64)' || 'unit tests' }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Get Compose uses: ./get-compose-action @@ -53,7 +53,7 @@ jobs: CONTAINER_ENGINE_PODMAN: ${{ matrix.container_engine == 'podman' && '1' || '0' }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Podman if: matrix.container_engine == 'podman' From 7ef1b36b90ada2b8545bd239019e332962a40fea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 19:05:35 +0100 Subject: [PATCH 224/305] build(deps): bump actions/create-github-app-token from 2.1.0 to 2.1.1 (#3885) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.1.0 to 2.1.1. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/0f859bf9e69e887678d5bbfbee594437cb440ffe...a8d616148505b5069dccd32f177bb87d7f39123b) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 2.1.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c7d447e130a..21115c4ce4c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@0f859bf9e69e887678d5bbfbee594437cb440ffe # v2.1.0 + uses: actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b # v2.1.1 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From 657a685cbef5e04d39b0033fadb9e9e6177b6b7c Mon Sep 17 00:00:00 2001 From: Iven Schlenther Date: Tue, 19 Aug 2025 20:39:04 +0200 Subject: [PATCH 225/305] fix(enhancement): search for permissions on docker container instead of host and combine it in one command for performance enhancement (#3890) * fix(enhancement): ensure correct ownership check before setting permissions of profiles * fix(enhancement): search for permissions on docker container instead of host and combine it in one command for performance enhancement Resolves #3882 * fix(enhancement): search for permissions on docker container instead of host --- install/ensure-correct-permissions-profiles-dir.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/ensure-correct-permissions-profiles-dir.sh b/install/ensure-correct-permissions-profiles-dir.sh index 5bdadecc70c..92792b26e50 100755 --- a/install/ensure-correct-permissions-profiles-dir.sh +++ b/install/ensure-correct-permissions-profiles-dir.sh @@ -5,8 +5,8 @@ echo "${_group}Ensuring correct permissions on profiles directory ..." # Check if the parent directory of /var/vroom/sentry-profiles is already owned by vroom:vroom -if [ "$(stat -c '%U:%G' /var/vroom)" = "vroom:vroom" ]; then - echo "Ownership of /var/vroom is already set to vroom:vroom. Skipping chown." +if [ "$($dcr --no-deps --entrypoint /bin/bash --user root vroom -c "stat -c '%U:%G' /var/vroom/sentry-profiles" 2>/dev/null)" = "vroom:vroom" ]; then + echo "Ownership of /var/vroom/sentry-profiles is already set to vroom:vroom. Skipping chown." else $dcr --no-deps --entrypoint /bin/bash --user root vroom -c 'chown -R vroom:vroom /var/vroom/sentry-profiles && chmod -R o+rwx /var/vroom/sentry-profiles' fi From 8641076786ab4650025daf0bb14d5b0656c08c56 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 20 Aug 2025 01:39:30 +0700 Subject: [PATCH 226/305] chore: resolve GHA code scanning alerts (#3889) Resolves https://github.com/getsentry/self-hosted/security/code-scanning/2 Resolves https://github.com/getsentry/self-hosted/security/code-scanning/4 Resolves https://github.com/getsentry/self-hosted/security/code-scanning/7 Resolves https://github.com/getsentry/self-hosted/security/code-scanning/14 Resolves https://github.com/getsentry/self-hosted/security/code-scanning/15 --- .github/workflows/enforce-license-compliance.yml | 3 +++ .github/workflows/pre-commit.yml | 3 +++ .github/workflows/release.yml | 2 ++ .github/workflows/shellcheck.yml | 4 +++- .github/workflows/test.yml | 6 ++++-- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/enforce-license-compliance.yml b/.github/workflows/enforce-license-compliance.yml index 02ca9d8e3f6..43ce1996390 100644 --- a/.github/workflows/enforce-license-compliance.yml +++ b/.github/workflows/enforce-license-compliance.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [master] +permissions: + contents: read + jobs: enforce-license-compliance: if: github.repository_owner == 'getsentry' diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 6a449b9da7c..1ba1d915924 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -5,6 +5,9 @@ on: push: branches: [master] +permissions: + contents: read + jobs: pre-commit: runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 21115c4ce4c..bbd7dfd659f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,6 +13,8 @@ on: # We also make this an hour after all others such as Sentry, # Snuba, and Relay to make sure their releases finish. - cron: "0 18 15 * *" +permissions: + contents: read jobs: release: if: github.repository_owner == 'getsentry' diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 889817caaf8..692da9f4a8f 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -1,4 +1,3 @@ ---- name: "ShellCheck" on: push: @@ -10,6 +9,9 @@ on: - "**.sh" branches: [master] +permissions: + contents: read + jobs: shellcheck: name: ShellCheck diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 99448af00c3..c2a431f7bae 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,4 @@ -permissions: - contents: read + name: Test on: # Run CI on all pushes to the master and release/** branches, and on all new @@ -17,6 +16,9 @@ concurrency: group: ${{ github.ref_name || github.sha }} cancel-in-progress: true +permissions: + contents: read + defaults: run: shell: bash From 2862432828a35b106dce38682b2ed6fb41c53d11 Mon Sep 17 00:00:00 2001 From: Frederik Spang Date: Sat, 23 Aug 2025 15:18:13 +0200 Subject: [PATCH 227/305] Add pgbouncer (#3884) * Add patch for pgbouncer * pgcat over pgbouncer * Add patch for .env file * Apply patches and add initial pgcat tolm file * feat: hardcode pgcat image * Fixes from review * Align usernames defaults * Remove postgres from default depends_on; Covered by pgcat by extension * Set user and password - pgcat maybe doesnt support host auth trust * Pool name maybe has to match, for some reason * Use healthcheck from pgcat PR * Reduce pool size, leave some for healthchecks and other clients running * Start pgcat for bash scripts with postgres * Update docker-compose.yml * Use pgbouncer * Revert to TRUST method --- docker-compose.yml | 20 +++++++++++++++++++- install/set-up-and-migrate-database.sh | 1 + sentry-admin.sh | 1 + sentry/sentry.conf.example.py | 2 +- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8873990cb3e..77a4a938e48 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,7 @@ x-sentry-defaults: &sentry_defaults <<: *depends_on-healthy kafka: <<: *depends_on-healthy - postgres: + pgbouncer: <<: *depends_on-healthy memcached: <<: *depends_on-default @@ -144,6 +144,24 @@ services: POSTGRES_HOST_AUTH_METHOD: "trust" volumes: - "sentry-postgres:/var/lib/postgresql/data" + pgbouncer: + image: "edoburu/pgbouncer:v1.24.1-p1" + healthcheck: + <<: *healthcheck_defaults + # Using default user "postgres" from sentry/sentry.conf.example.py or value of POSTGRES_USER if provided + test: ["CMD-SHELL", "psql -U postgres -p 5432 -h 127.0.0.1 -tA -c \"select 1;\" -d postgres >/dev/null"] + depends_on: + postgres: + <<: *depends_on-healthy + environment: + DB_USER: ${POSTGRES_USER:-postgres} + DB_HOST: postgres + DB_NAME: postgres + AUTH_TYPE: trust + POOL_MODE: transaction + ADMIN_USERS: postgres,sentry + MAX_CLIENT_CONN: 10000 + kafka: <<: *restart_policy image: "confluentinc/cp-kafka:7.6.1" diff --git a/install/set-up-and-migrate-database.sh b/install/set-up-and-migrate-database.sh index 5ddf324c0b8..debebd2531d 100644 --- a/install/set-up-and-migrate-database.sh +++ b/install/set-up-and-migrate-database.sh @@ -3,6 +3,7 @@ echo "${_group}Setting up / migrating database ..." if [[ -z "${SKIP_SENTRY_MIGRATIONS:-}" ]]; then # Fixes https://github.com/getsentry/self-hosted/issues/2758, where a migration fails due to indexing issue start_service_and_wait_ready postgres + start_service_and_wait_ready pgbouncer os=$($dc exec postgres cat /etc/os-release | grep 'ID=debian') if [[ -z $os ]]; then diff --git a/sentry-admin.sh b/sentry-admin.sh index aeea2b36845..ef5608488f9 100755 --- a/sentry-admin.sh +++ b/sentry-admin.sh @@ -24,6 +24,7 @@ on the host filesystem. Commands that write files should write them to the '/sen # Actual invocation that runs the command in the container. invocation() { start_service_and_wait_ready postgres + start_service_and_wait_ready pgbouncer start_service_and_wait_ready redis --wait $dcr --no-deps -v "$VOLUME_MAPPING" -T -e SENTRY_LOG_LEVEL=CRITICAL web "$@" 2>&1 } diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 826f43ae2d6..944dc6399b3 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -48,7 +48,7 @@ def get_internal_network(): "NAME": "postgres", "USER": "postgres", "PASSWORD": "", - "HOST": "postgres", + "HOST": "pgbouncer", "PORT": "", } } From b7bb06470e150410d74ba41fa68c69ac884ee3df Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Sat, 23 Aug 2025 17:06:20 +0330 Subject: [PATCH 228/305] Revert "increase postgres max_connections above 100 connections (#2740)" (#3899) This reverts commit 7691addcb631fee42389896cf4eead0794f11a9d. --- .env | 3 --- docker-compose.yml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.env b/.env index ba8cf6267b7..dfe279267f8 100644 --- a/.env +++ b/.env @@ -24,8 +24,5 @@ HEALTHCHECK_FILE_INTERVAL=60s HEALTHCHECK_FILE_TIMEOUT=10s HEALTHCHECK_FILE_RETRIES=3 HEALTHCHECK_FILE_START_PERIOD=600s -# Caution: Raising max connections of postgres increases CPU and RAM usage -# see https://github.com/getsentry/self-hosted/pull/2740 for more information -POSTGRES_MAX_CONNECTIONS=100 # Set SETUP_JS_SDK_ASSETS to 1 to enable the setup of JS SDK assets # SETUP_JS_SDK_ASSETS=1 diff --git a/docker-compose.yml b/docker-compose.yml index 77a4a938e48..7d89d34c394 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -139,7 +139,7 @@ services: # Using default user "postgres" from sentry/sentry.conf.example.py or value of POSTGRES_USER if provided test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"] command: - ["postgres", "-c", "max_connections=${POSTGRES_MAX_CONNECTIONS:-100}"] + ["postgres"] environment: POSTGRES_HOST_AUTH_METHOD: "trust" volumes: From 67c32e883dae0021f5be7e31fdbcefc3cff6c880 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 23 Aug 2025 21:15:07 +0700 Subject: [PATCH 229/305] chore(deps): bump patches version (#3879) Except nginx, they don't seem to have any breaking change. See https://nginx.org/en/CHANGES Other than nginx, patches version are available. --- docker-compose.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7d89d34c394..2290a301429 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -115,7 +115,7 @@ services: test: echo stats | nc 127.0.0.1 11211 redis: <<: *restart_policy - image: "redis:6.2.14-alpine" + image: "redis:6.2.19-alpine" healthcheck: <<: *healthcheck_defaults test: redis-cli ping | grep PONG @@ -133,7 +133,7 @@ services: postgres: <<: *restart_policy # Using the same postgres version as Sentry dev for consistency purposes - image: "postgres:14.11" + image: "postgres:14.19-bookworm" healthcheck: <<: *healthcheck_defaults # Using default user "postgres" from sentry/sentry.conf.example.py or value of POSTGRES_USER if provided @@ -164,7 +164,7 @@ services: kafka: <<: *restart_policy - image: "confluentinc/cp-kafka:7.6.1" + image: "confluentinc/cp-kafka:7.6.6" environment: # https://docs.confluent.io/platform/current/installation/docker/config-reference.html#cp-kakfa-example KAFKA_PROCESS_ROLES: "broker,controller" @@ -656,7 +656,7 @@ services: <<: *restart_policy ports: - "$SENTRY_BIND:80/tcp" - image: "nginx:1.25.4-alpine" + image: "nginx:1.29.1-alpine" volumes: - type: bind read_only: true From de2139890d3d6b28682f2a07855e9aefc0b030ae Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 2 Sep 2025 21:35:33 +0700 Subject: [PATCH 230/305] fix: ensuring vroom permission should be skipped on errors-only (#3911) * fix: ensuring vroom permission should be skipped on errors-only * feat: enable swap on all runners * feat: don't exit on install script --- action.yaml | 2 +- ...ensure-correct-permissions-profiles-dir.sh | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/action.yaml b/action.yaml index 0a655e53bd5..5c291eede3e 100644 --- a/action.yaml +++ b/action.yaml @@ -144,8 +144,8 @@ runs: - name: Setup swapfile shell: bash - if: runner.arch == 'X64' || runner.arch == 'X86' run: | + sudo swapoff -a sudo fallocate -l 16G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile diff --git a/install/ensure-correct-permissions-profiles-dir.sh b/install/ensure-correct-permissions-profiles-dir.sh index 92792b26e50..2fd95b885e6 100755 --- a/install/ensure-correct-permissions-profiles-dir.sh +++ b/install/ensure-correct-permissions-profiles-dir.sh @@ -2,13 +2,16 @@ # TODO: Remove this after the next hard-stop -echo "${_group}Ensuring correct permissions on profiles directory ..." +# Should only run when `$COMPOSE_PROFILES` is set to `feature-complete` +if [[ "$COMPOSE_PROFILES" == "feature-complete" ]]; then + echo "${_group}Ensuring correct permissions on profiles directory ..." -# Check if the parent directory of /var/vroom/sentry-profiles is already owned by vroom:vroom -if [ "$($dcr --no-deps --entrypoint /bin/bash --user root vroom -c "stat -c '%U:%G' /var/vroom/sentry-profiles" 2>/dev/null)" = "vroom:vroom" ]; then - echo "Ownership of /var/vroom/sentry-profiles is already set to vroom:vroom. Skipping chown." -else - $dcr --no-deps --entrypoint /bin/bash --user root vroom -c 'chown -R vroom:vroom /var/vroom/sentry-profiles && chmod -R o+rwx /var/vroom/sentry-profiles' -fi + # Check if the parent directory of /var/vroom/sentry-profiles is already owned by vroom:vroom + if [ "$($dcr --no-deps --entrypoint /bin/bash --user root vroom -c "stat -c '%U:%G' /var/vroom/sentry-profiles" 2>/dev/null)" = "vroom:vroom" ]; then + echo "Ownership of /var/vroom/sentry-profiles is already set to vroom:vroom. Skipping chown." + else + $dcr --no-deps --entrypoint /bin/bash --user root vroom -c 'chown -R vroom:vroom /var/vroom/sentry-profiles && chmod -R o+rwx /var/vroom/sentry-profiles' + fi -echo "${_endgroup}" + echo "${_endgroup}" +fi From f5773e8ed525f527feda8a16d952b9bfa1fcc9f0 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 3 Sep 2025 00:21:03 +0700 Subject: [PATCH 231/305] feat: enable Logs feature (#3912) * feat: enable Logs feature * feat: enable swap on all runners See https://github.com/getsentry/self-hosted/pull/3911/commits/ce819b8d99eac7f20c786492fe3c5b434c14e753 --- _integration-test/test_01_basics.py | 29 +++++++++++++++++++++++++++++ sentry/sentry.conf.example.py | 7 +++++++ 2 files changed, 36 insertions(+) diff --git a/_integration-test/test_01_basics.py b/_integration-test/test_01_basics.py index b759f629730..caa7c6ff519 100644 --- a/_integration-test/test_01_basics.py +++ b/_integration-test/test_01_basics.py @@ -11,6 +11,7 @@ import httpx import pytest import sentry_sdk +from sentry_sdk import logger as sentry_logger from bs4 import BeautifulSoup from cryptography import x509 from cryptography.hazmat.backends import default_backend @@ -406,6 +407,34 @@ def placeholder_fn(): ) +def test_receive_logs_events(client_login): + client, _ = client_login + sentry_sdk.init( + dsn=get_sentry_dsn(client), profiles_sample_rate=1.0, traces_sample_rate=1.0, enable_logs=True, + ) + + sentry_logger.trace('Starting database connection {database}', database="users") + sentry_logger.debug('Cache miss for user {user_id}', user_id=123) + sentry_logger.info('Updated global cache') + sentry_logger.warning('Rate limit reached for endpoint {endpoint}', endpoint='/api/results/') + sentry_logger.error('Failed to process payment. Order: {order_id}. Amount: {amount}', order_id="or_2342", amount=99.99) + sentry_logger.fatal('Database {database} connection pool exhausted', database="users") + sentry_logger.error( + 'Payment processing failed', + attributes={ + 'payment.provider': 'stripe', + 'payment.method': 'credit_card', + 'payment.currency': 'USD', + 'user.subscription_tier': 'premium' + } + ) + + poll_for_response( + f"{SENTRY_TEST_HOST}/api/0/organizations/sentry/events/?dataset=ourlogs&field=sentry.item_id&field=project.id&field=trace&field=severity_number&field=severity&field=timestamp&field=timestamp_precise&field=observed_timestamp&field=message&project=1&statsPeriod=1h", + client, + lambda x: len(json.loads(x)["data"]) > 0, + ) + def test_customizations(): commands = [ [ diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 944dc6399b3..a96e5e6f2ab 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -350,6 +350,13 @@ def get_internal_network(): "organizations:uptime", "organizations:uptime-create-issues", ) + # Logs related flags + + ( + "organizations:ourlogs-enabled", + "organizations:ourlogs-ingestion", + "organizations:ourlogs-stats", + "organizations:ourlogs-replay-ui", + ) } ) From af32d373b253cc79661f118cb857283a523acbca Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 3 Sep 2025 06:05:57 +0700 Subject: [PATCH 232/305] test: run errors-only integration tests (#3910) --- .github/workflows/test.yml | 4 +++- _integration-test/test_01_basics.py | 1 + action.yaml | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c2a431f7bae..49298277c4f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -48,7 +48,8 @@ jobs: matrix: os: [ubuntu-24.04, ubuntu-24.04-arm] container_engine: ['docker'] # TODO: add 'podman' into the list - name: ${{ matrix.os == 'ubuntu-24.04-arm' && (matrix.container_engine == 'docker' && 'integration test (arm64)' || 'integration test (arm64 podman)') || (matrix.container_engine == 'docker' && 'integration test' || 'integration test (podman)') }} + compose_profiles: ['feature-complete', 'errors-only'] + name: ${{ format('integration test{0}{1}{2}', matrix.os == 'ubuntu-24.04-arm' && ' (arm64)' || '', matrix.container_engine == 'podman' && ' (podman)' || '', matrix.compose_profiles == 'errors-only' && ' (errors-only)' || '') }} env: REPORT_SELF_HOSTED_ISSUES: 0 SELF_HOSTED_TESTING_DSN: ${{ vars.SELF_HOSTED_TESTING_DSN }} @@ -71,4 +72,5 @@ jobs: - name: Use action from local checkout uses: './' with: + compose_profiles: ${{ matrix.compose_profiles }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/_integration-test/test_01_basics.py b/_integration-test/test_01_basics.py index caa7c6ff519..bc9eb55d48d 100644 --- a/_integration-test/test_01_basics.py +++ b/_integration-test/test_01_basics.py @@ -380,6 +380,7 @@ def test_custom_certificate_authorities(): del os.environ["COMPOSE_FILE"] +@pytest.mark.skipif(os.environ.get("COMPOSE_PROFILES") != "feature-complete", reason="Only run if feature-complete") def test_receive_transaction_events(client_login): client, _ = client_login sentry_sdk.init( diff --git a/action.yaml b/action.yaml index 5c291eede3e..563e06d40d6 100644 --- a/action.yaml +++ b/action.yaml @@ -6,6 +6,9 @@ inputs: image_url: required: false description: "The URL to the built relay, snuba, sentry image to test against." + compose_profiles: + required: false + description: "Docker Compose profile to use. Defaults to feature-complete." CODECOV_TOKEN: required: false description: "The Codecov token to upload coverage." @@ -18,6 +21,7 @@ runs: env: PROJECT_NAME: ${{ inputs.project_name }} IMAGE_URL: ${{ inputs.image_url }} + COMPOSE_PROFILES: ${{ inputs.compose_profiles }} run: | if [[ -n "$PROJECT_NAME" && -n "$IMAGE_URL" ]]; then image_var=$(echo "${PROJECT_NAME}_IMAGE" | tr '[:lower:]' '[:upper:]') @@ -30,6 +34,14 @@ runs: exit 1 fi + # `COMPOSE_PROFILES` may only be `feature-complete` or `errors-only` + if [[ "$COMPOSE_PROFILES" != "" && "$COMPOSE_PROFILES" != "feature-complete" && "$COMPOSE_PROFILES" != "errors-only" ]]; then + echo "COMPOSE_PROFILES must be either unset, or set to either 'feature-complete' or 'errors-only'." + exit 1 + else + echo "COMPOSE_PROFILES=$COMPOSE_PROFILES" >> ${{ github.action_path }}/.env + fi + - name: Setup dev environment shell: bash run: | @@ -155,6 +167,8 @@ runs: - name: Integration Test shell: bash + env: + COMPOSE_PROFILES: ${{ inputs.compose_profiles }} run: | sudo chown root /usr/bin/rsync && sudo chmod u+s /usr/bin/rsync rsync -aW --super --numeric-ids --no-compress --mkpath \ From 85365f1149f9cc61e5cd04e8d81783ceb62cf782 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Wed, 3 Sep 2025 02:36:43 +0330 Subject: [PATCH 233/305] Improve nginx depends_on policy (#3914) --- docker-compose.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2290a301429..a7a276a6a40 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -671,8 +671,12 @@ services: - "/usr/bin/curl" - http://localhost depends_on: - - web - - relay + web: + <<: *depends_on-healthy + restart: true + relay: + <<: *depends_on-healthy + restart: true relay: <<: *restart_policy image: "$RELAY_IMAGE" From e3e7789853fc7316dba98415282e066e504c7825 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 3 Sep 2025 19:25:21 +0700 Subject: [PATCH 234/305] fix(tests): skip logs event test for errors-only (#3915) --- _integration-test/test_01_basics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/_integration-test/test_01_basics.py b/_integration-test/test_01_basics.py index bc9eb55d48d..a552988baa1 100644 --- a/_integration-test/test_01_basics.py +++ b/_integration-test/test_01_basics.py @@ -408,6 +408,7 @@ def placeholder_fn(): ) +@pytest.mark.skipif(os.environ.get("COMPOSE_PROFILES") != "feature-complete", reason="Only run if feature-complete") def test_receive_logs_events(client_login): client, _ = client_login sentry_sdk.init( From 53004dcbc0af9251157fa2cb60d94b0a2552ed2d Mon Sep 17 00:00:00 2001 From: Frederik Spang Date: Sat, 6 Sep 2025 07:32:00 +0200 Subject: [PATCH 235/305] Add restart policy to pgbouncer service (#3925) --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index a7a276a6a40..54a161f375d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -145,6 +145,7 @@ services: volumes: - "sentry-postgres:/var/lib/postgresql/data" pgbouncer: + <<: *restart_policy image: "edoburu/pgbouncer:v1.24.1-p1" healthcheck: <<: *healthcheck_defaults From 2be8c79d64ea937178cb739a983f20ac368af3fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 08:41:05 +0700 Subject: [PATCH 236/305] build(deps): bump actions/setup-python from 5 to 6 (#3927) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 1ba1d915924..35e1183b6e3 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: 3.x - uses: pre-commit/action@v3.0.1 From 8ad99169994e6c67f50488e27646d30c9ca80703 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 12 Sep 2025 05:08:06 +0700 Subject: [PATCH 237/305] feat: query against `eap` dataset instead of `metrics` dataset for spans (#3923) --- sentry/sentry.conf.example.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index a96e5e6f2ab..3bcd1ff3a7a 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -316,12 +316,15 @@ def get_internal_network(): # Performance/Tracing/Spans related flags + ( "organizations:performance-view", + "organizations:span-stats", "organizations:visibility-explore-view", + "organizations:visibility-explore-range-high", "organizations:transaction-metrics-extraction", "organizations:indexed-spans-extraction", "organizations:insights-entry-points", "organizations:insights-initial-modules", "organizations:insights-addon-modules", + "organizations:insights-modules-use-eap", "organizations:standalone-span-ingestion", "organizations:starfish-mobile-appstart", "projects:span-metrics-extraction", From 7164e22494cb64606908eb502762de6870ee2181 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 12 Sep 2025 07:17:53 +0700 Subject: [PATCH 238/305] feat: enable `issue-views` flag (#3922) --- sentry/sentry.conf.example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 3bcd1ff3a7a..9c58f55752f 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -293,6 +293,7 @@ def get_internal_network(): for feature in ( "organizations:discover", "organizations:global-views", + "organizations:issue-views", "organizations:incidents", "organizations:integrations-issue-basic", "organizations:integrations-issue-sync", From ce452944917d0848563fbefecd00661a7ef02e1c Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 12 Sep 2025 07:39:27 +0700 Subject: [PATCH 239/305] chore(deps): bump clickhouse to 25.3 (#3878) * chore(deps): bump clickhouse to 25.3 * fix: wrong volume path for clickhouse default password: --- clickhouse/default-password.xml | 10 ++++++++++ docker-compose.yml | 12 ++++++++---- install/upgrade-clickhouse.sh | 34 ++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 clickhouse/default-password.xml diff --git a/clickhouse/default-password.xml b/clickhouse/default-password.xml new file mode 100644 index 00000000000..13588039cba --- /dev/null +++ b/clickhouse/default-password.xml @@ -0,0 +1,10 @@ + + + + + + ::/0 + + + + diff --git a/docker-compose.yml b/docker-compose.yml index 54a161f375d..6d59d10700b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -206,7 +206,7 @@ services: build: context: ./clickhouse args: - BASE_IMAGE: "altinity/clickhouse-server:23.8.11.29.altinitystable" + BASE_IMAGE: "altinity/clickhouse-server:25.3.6.10034.altinitystable" ulimits: nofile: soft: 262144 @@ -214,10 +214,14 @@ services: volumes: - "sentry-clickhouse:/var/lib/clickhouse" - "sentry-clickhouse-log:/var/log/clickhouse-server" - - type: bind + - type: "bind" + read_only: true + source: "./clickhouse/config.xml" + target: "/etc/clickhouse-server/config.d/sentry.xml" + - type: "bind" read_only: true - source: ./clickhouse/config.xml - target: /etc/clickhouse-server/config.d/sentry.xml + source: "./clickhouse/default-password.xml" + target: "/etc/clickhouse-server/users.d/default-password.xml" environment: # This limits Clickhouse's memory to 30% of the host memory # If you have high volume and your search return incomplete results diff --git a/install/upgrade-clickhouse.sh b/install/upgrade-clickhouse.sh index 93456b8ddbe..7ac7e826e61 100644 --- a/install/upgrade-clickhouse.sh +++ b/install/upgrade-clickhouse.sh @@ -14,15 +14,47 @@ if $ps_command | grep -q clickhouse; then # Start clickhouse if it is not already running start_service_and_wait_ready clickhouse - # In order to get to 23.8, we need to first upgrade go from 21.8 -> 22.8 -> 23.3 -> 23.8 + # In order to get to 25.3, we need to first upgrade go from 21.8 -> 22.8 -> 23.3 -> 23.8 -> 24.8 -> 25.3 version=$($dc exec clickhouse clickhouse-client -q 'SELECT version()') if [[ "$version" == "21.8.13.1.altinitystable" || "$version" == "21.8.12.29.altinitydev.arm" ]]; then + echo "Detected clickhouse version $version" $dc down clickhouse + + echo "Upgrading clickhouse to 22.8" $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:22.8.15.25.altinitystable clickhouse start_service_and_wait_ready clickhouse $dc down clickhouse + + echo "Upgrading clickhouse to 23.3" $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:23.3.19.33.altinitystable clickhouse start_service_and_wait_ready clickhouse + $dc down clickhouse + + echo "Upgrading clickhouse to 23.8" + $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:23.8.11.29.altinitystable clickhouse + start_service_and_wait_ready clickhouse + $dc down clickhouse + + echo "Upgrading clickhouse to 24.8" + $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:24.8.14.10459.altinitystable clickhouse + start_service_and_wait_ready clickhouse + $dc down clickhouse + + echo "Upgrading clickhouse to 25.3" + $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:25.3.6.10034.altinitystable clickhouse + start_service_and_wait_ready clickhouse + elif [[ "$version" == "23.8.11.29.altinitystable" ]]; then + echo "Detected clickhouse version $version" + $dc down clickhouse + + echo "Upgrading clickhouse to 24.8" + $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:24.8.14.10459.altinitystable clickhouse + start_service_and_wait_ready clickhouse + $dc down clickhouse + + echo "Upgrading clickhouse to 25.3" + $dcb $build_arg BASE_IMAGE=altinity/clickhouse-server:25.3.6.10034.altinitystable clickhouse + start_service_and_wait_ready clickhouse else echo "Detected clickhouse version $version. Skipping upgrades!" fi From 2e7a3ff7ad9435848b5052d1aa91ae42695e76d8 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 12 Sep 2025 21:02:59 +0700 Subject: [PATCH 240/305] feat: install script to migrate sentry.conf.py config to use pgbouncer (#3898) --- _unit-test/migrate-pgbouncer-test.sh | 197 +++++++++++++++++++++++++++ install/migrate-pgbouncer.sh | 82 +++++++++++ install/parse-cli.sh | 8 ++ 3 files changed, 287 insertions(+) create mode 100755 _unit-test/migrate-pgbouncer-test.sh create mode 100644 install/migrate-pgbouncer.sh diff --git a/_unit-test/migrate-pgbouncer-test.sh b/_unit-test/migrate-pgbouncer-test.sh new file mode 100755 index 00000000000..b78ee633c04 --- /dev/null +++ b/_unit-test/migrate-pgbouncer-test.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env bash + +source _unit-test/_test_setup.sh +source install/dc-detect-version.sh + +source install/ensure-files-from-examples.sh +cp $SENTRY_CONFIG_PY /tmp/sentry_conf_py +# Set the flag to apply automatic updates +export APPLY_AUTOMATIC_CONFIG_UPDATES=1 + +# Declare expected content +expected_db_config=$( + cat <<'EOF' +DATABASES = { + "default": { + "ENGINE": "sentry.db.postgres", + "NAME": "postgres", + "USER": "postgres", + "PASSWORD": "", + "HOST": "pgbouncer", + "PORT": "", + } +} +EOF +) + +echo "Test 1 (pre 25.9.0 release)" +# Modify the `DATABASES = {` to the next `}` line, with: +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "postgres", +# "PASSWORD": "", +# "HOST": "postgres", +# "PORT": "", +# } +# } + +# Create the replacement text in a temp file +cat >/tmp/sentry_conf_py_db_config <<'EOF' +DATABASES = { + "default": { + "ENGINE": "sentry.db.postgres", + "NAME": "postgres", + "USER": "postgres", + "PASSWORD": "", + "HOST": "postgres", + "PORT": "", + } +} +EOF + +# Replace the block +sed -i '/^DATABASES = {$/,/^}$/{ + /^DATABASES = {$/r /tmp/sentry_conf_py_db_config + d +}' $SENTRY_CONFIG_PY + +# Clean up +rm /tmp/sentry_conf_py_db_config + +source install/migrate-pgbouncer.sh + +# Extract actual content +actual_db_config=$(sed -n '/^DATABASES = {$/,/^}$/p' $SENTRY_CONFIG_PY) + +# Compare +if [ "$actual_db_config" = "$expected_db_config" ]; then + echo "DATABASES section is correct" +else + echo "DATABASES section does not match" + echo "Expected:" + echo "$expected_db_config" + echo "Actual:" + echo "$actual_db_config" + exit 1 +fi + +# Reset the file +rm $SENTRY_CONFIG_PY +cp /tmp/sentry_conf_py $SENTRY_CONFIG_PY + +echo "Test 2 (post 25.9.0 release)" +# Modify the `DATABASES = {` to the next `}` line, with: +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "postgres", +# "PASSWORD": "", +# "HOST": "pgbouncer", +# "PORT": "", +# } +# } + +# Create the replacement text in a temp file +cat >/tmp/sentry_conf_py_db_config <<'EOF' +DATABASES = { + "default": { + "ENGINE": "sentry.db.postgres", + "NAME": "postgres", + "USER": "postgres", + "PASSWORD": "", + "HOST": "pgbouncer", + "PORT": "", + } +} +EOF + +# Replace the block +sed -i '/^DATABASES = {$/,/^}$/{ + /^DATABASES = {$/r /tmp/sentry_conf_py_db_config + d +}' $SENTRY_CONFIG_PY + +# Clean up +rm /tmp/sentry_conf_py_db_config + +source install/migrate-pgbouncer.sh + +# Extract actual content +actual_db_config=$(sed -n '/^DATABASES = {$/,/^}$/p' $SENTRY_CONFIG_PY) + +# Compare +if [ "$actual_db_config" = "$expected_db_config" ]; then + echo "DATABASES section is correct" +else + echo "DATABASES section does not match" + echo "Expected:" + echo "$expected_db_config" + echo "Actual:" + echo "$actual_db_config" + exit 1 +fi + +# Reset the file +rm $SENTRY_CONFIG_PY +cp /tmp/sentry_conf_py $SENTRY_CONFIG_PY + +echo "Test 3 (custom postgres config)" +# Modify the `DATABASES = {` to the next `}` line, with: +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "sentry", +# "PASSWORD": "sentry", +# "HOST": "postgres.internal", +# "PORT": "5432", +# } +# } + +# Create the replacement text in a temp file +cat >/tmp/sentry_conf_py_db_config <<'EOF' +DATABASES = { + "default": { + "ENGINE": "sentry.db.postgres", + "NAME": "postgres", + "USER": "sentry", + "PASSWORD": "sentry", + "HOST": "postgres.internal", + "PORT": "5432", + } +} +EOF + +# Replace the block +sed -i '/^DATABASES = {$/,/^}$/{ + /^DATABASES = {$/r /tmp/sentry_conf_py_db_config + d +}' $SENTRY_CONFIG_PY + +# Clean up +rm /tmp/sentry_conf_py_db_config + +source install/migrate-pgbouncer.sh + +# Extract actual content +actual_db_config=$(sed -n '/^DATABASES = {$/,/^}$/p' $SENTRY_CONFIG_PY) + +# THe file should NOT be modified +if [ "$actual_db_config" = "$expected_db_config" ]; then + echo "DATABASES section SHOULD NOT be modified" + echo "Expected:" + echo "$expected_db_config" + echo "Actual:" + echo "$actual_db_config" + exit 1 +else + echo "DATABASES section is correct" +fi + +# Remove the file +rm $SENTRY_CONFIG_PY /tmp/sentry_conf_py + +report_success diff --git a/install/migrate-pgbouncer.sh b/install/migrate-pgbouncer.sh new file mode 100644 index 00000000000..8c698c72d92 --- /dev/null +++ b/install/migrate-pgbouncer.sh @@ -0,0 +1,82 @@ +echo "${_group}Migrating Postgres config to PGBouncer..." +# If users has this EXACT configuration on their `sentry.conf.py` file: +# ```python +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "postgres", +# "PASSWORD": "", +# "HOST": "postgres", +# "PORT": "", +# } +# } +# ``` +# We need to migrate it to this configuration: +# ```python +# DATABASES = { +# "default": { +# "ENGINE": "sentry.db.postgres", +# "NAME": "postgres", +# "USER": "postgres", +# "PASSWORD": "", +# "HOST": "pgbouncer", +# "PORT": "", +# } +# } +# ``` + +if sed -n '/^DATABASES = {$/,/^}$/p' "$SENTRY_CONFIG_PY" | grep -q '"HOST": "postgres"'; then + apply_config_changes_pgbouncer=0 + if [[ -z "${APPLY_AUTOMATIC_CONFIG_UPDATES:-}" ]]; then + echo + echo "We added PGBouncer to the default Compose stack, and to use that" + echo "you will need to modify your sentry.conf.py file contents." + echo "Do you want us to make this change automatically for you?" + echo + + yn="" + until [ ! -z "$yn" ]; do + read -p "y or n? " yn + case $yn in + y | yes | 1) + export apply_config_changes_pgbouncer=1 + echo + echo -n "Thank you." + ;; + n | no | 0) + export apply_config_changes_pgbouncer=0 + echo + echo -n "Alright, you will need to update your sentry.conf.py file manually before running 'docker compose up' or remove the $(pgbouncer) service if you don't want to use that." + ;; + *) yn="" ;; + esac + done + + echo + echo "To avoid this prompt in the future, use one of these flags:" + echo + echo " --apply-automatic-config-updates" + echo " --no-apply-automatic-config-updates" + echo + echo "or set the APPLY_AUTOMATIC_CONFIG_UPDATES environment variable:" + echo + echo " APPLY_AUTOMATIC_CONFIG_UPDATES=1 to apply automatic updates" + echo " APPLY_AUTOMATIC_CONFIG_UPDATES=0 to not apply automatic updates" + echo + sleep 5 + fi + + if [[ "$APPLY_AUTOMATIC_CONFIG_UPDATES" == 1 || "$apply_config_changes_pgbouncer" == 1 ]]; then + echo "Migrating $SENTRY_CONFIG_PY to use PGBouncer" + sed -i 's/"HOST": "postgres"/"HOST": "pgbouncer"/' "$SENTRY_CONFIG_PY" + echo "Migrated $SENTRY_CONFIG_PY to use PGBouncer" + fi +elif sed -n '/^DATABASES = {$/,/^}$/p' "$SENTRY_CONFIG_PY" | grep -q '"HOST": "pgbouncer"'; then + echo "Found pgbouncer in $SENTRY_CONFIG_PY, I'm assuming you're good! :)" +else + echo "⚠️ You don't have standard configuration for Postgres in $SENTRY_CONFIG_PY, skipping pgbouncer migration. I'm assuming you know what you're doing." + echo " For more information about PGBouncer, refer to https://github.com/getsentry/self-hosted/pull/3884" +fi + +echo "${_endgroup}" diff --git a/install/parse-cli.sh b/install/parse-cli.sh index b342033ca08..aec899c6398 100644 --- a/install/parse-cli.sh +++ b/install/parse-cli.sh @@ -31,6 +31,10 @@ Options: self-hosted instance upstream to Sentry. --container-engine-podman Use podman as the container engine. + --apply-automatic-config-updates + Apply automatic config file updates. + --no-apply-automatic-config-updates + Do not apply automatic config file updates. EOF } @@ -41,6 +45,7 @@ depwarn() { if [ ! -z "${SKIP_USER_PROMPT:-}" ]; then depwarn "SKIP_USER_PROMPT variable" "SKIP_USER_CREATION" SKIP_USER_CREATION="${SKIP_USER_PROMPT}" + APPLY_AUTOMATIC_CONFIG_UPDATES="${SKIP_USER_PROMPT}" fi SKIP_USER_CREATION="${SKIP_USER_CREATION:-}" @@ -49,6 +54,7 @@ SKIP_COMMIT_CHECK="${SKIP_COMMIT_CHECK:-}" REPORT_SELF_HOSTED_ISSUES="${REPORT_SELF_HOSTED_ISSUES:-}" SKIP_SSE42_REQUIREMENTS="${SKIP_SSE42_REQUIREMENTS:-}" CONTAINER_ENGINE_PODMAN="${CONTAINER_ENGINE_PODMAN:-}" +APPLY_AUTOMATIC_CONFIG_UPDATES="${APPLY_AUTOMATIC_CONFIG_UPDATES:-}" while (($#)); do case "$1" in @@ -71,6 +77,8 @@ while (($#)); do --no-report-self-hosted-issues) REPORT_SELF_HOSTED_ISSUES=0 ;; --skip-sse42-requirements) SKIP_SSE42_REQUIREMENTS=1 ;; --container-engine-podman) CONTAINER_ENGINE_PODMAN=1 ;; + --apply-automatic-config-updates) APPLY_AUTOMATIC_CONFIG_UPDATES=1 ;; + --no-apply-automatic-config-updates) APPLY_AUTOMATIC_CONFIG_UPDATES=0 ;; --) ;; *) echo "Unexpected argument: $1. Use --help for usage information." From 440b6585fd888f7e09e051e9c02595ede7d5671c Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 12 Sep 2025 20:24:31 -0400 Subject: [PATCH 241/305] feat(tasks): Remove taskworker option override and add worker healthcheck (#3933) feat(tasks) Remove taskworker option override and add worker healthcheck Along with getsentry/sentry#99374 and this change taskworkers will be enabled by default in self-hosted. I've left the celery workers active to smooth over any tasks that are in-flight during an upgrade. Add a worker healtcheck as we have one now. Refs STREAM-450 --- docker-compose.yml | 4 +++- sentry/sentry.conf.example.py | 6 ------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6d59d10700b..abd0b98f1a3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -721,7 +721,9 @@ services: command: run taskworker-scheduler taskworker: <<: *sentry_defaults - command: run taskworker --concurrency=4 --rpc-host=taskbroker:50051 + command: run taskworker --concurrency=4 --rpc-host=taskbroker:50051 --health-check-file-path=/tmp/health.txt + healthcheck: + <<: *file_healthcheck_defaults vroom: <<: *restart_policy image: "$VROOM_IMAGE" diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 9c58f55752f..7fef845fb5d 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -456,9 +456,3 @@ def get_internal_network(): # } # SENTRY_METRICS_SAMPLE_RATE = 1.0 # Adjust this to your needs, default is 1.0 # SENTRY_METRICS_PREFIX = "sentry." # Adjust this to your needs, default is "sentry." - -######### -# Tasks # -######### -# Disable taskworker and continue using celery. -SENTRY_OPTIONS["taskworker.enabled"] = False From 84f904f7a15698cc5d8f0ce492612cd057f36721 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 13 Sep 2025 01:48:56 +0100 Subject: [PATCH 242/305] feat: Use S3 node store with seaweedfs (#3498) * feat: Use S3 node store with garage * lol, fix bash * moar bash * lol * hate bash * fix moar bash * Add healthcheck to garage service Co-authored-by: Reinaldy Rafli * revert +x * fix healthcheck, fix config * add env var for garage size * use better compression level * simpler garage config * add migration support * feat: use seaweedfs as nodestore backend (#3842) * feat: seaweedfs as s3 nodestore backend * fix: 'server' was missing for seaweed * feat: remove minimum volume free space * feat: specify hostname on ip * fix: grpc port on seaweed should be `-{service}.port.grpc` instead of `-{service}.grpcPort` * fix: wrong access key & secret key; use localhost for internal comms * fix: create index directory * test: add sentry-seaweedfs volume into expected volumes * debug: aaaaaaaaaaaaaaaaaaaaaaarrrrggggggghhhhhhhhhhhhhhh * test: correct ordering for expected volumes * chore: seaweedfs healthcheck to multiple urls See https://stackoverflow.com/a/14578575/3153224 * chore: add swap for arm64 runners * ci: debug memory issues for arm64 runners * ci: turn off swapfile first Turns out the arm64 runners already have 3GB of swap * feat: nodestore config update behind a prompt/flag * feat: set s3 lifecycle policy * fix: seaweed is a busybox * fix: try xml policy * fix: go back to simplified json * Revert "fix: go back to simplified json" This reverts commit 2f1575dfe33db6f781b09d09b01f5382716b8826. * chore: reword debug lifecycle policy * fix: don't pollute APPLY_AUTOMATIC_CONFIG_UPDATES variable --------- Co-authored-by: Reinaldy Rafli --- _unit-test/create-docker-volumes-test.sh | 1 + docker-compose.yml | 43 +++++++++++ install.sh | 1 + install/bootstrap-s3-nodestore.sh | 91 ++++++++++++++++++++++++ install/create-docker-volumes.sh | 1 + sentry/Dockerfile | 6 +- sentry/sentry.conf.example.py | 25 +++++++ 7 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 install/bootstrap-s3-nodestore.sh diff --git a/_unit-test/create-docker-volumes-test.sh b/_unit-test/create-docker-volumes-test.sh index 2cb9b962a8b..83591d3aa85 100755 --- a/_unit-test/create-docker-volumes-test.sh +++ b/_unit-test/create-docker-volumes-test.sh @@ -14,6 +14,7 @@ sentry-data sentry-kafka sentry-postgres sentry-redis +sentry-seaweedfs sentry-symbolicator" before=$(get_volumes) diff --git a/docker-compose.yml b/docker-compose.yml index abd0b98f1a3..47f0b31844c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,6 +42,8 @@ x-sentry-defaults: &sentry_defaults <<: *depends_on-default smtp: <<: *depends_on-default + seaweedfs: + <<: *depends_on-default snuba-api: <<: *depends_on-default symbolicator: @@ -238,6 +240,45 @@ services: interval: 10s timeout: 10s retries: 30 + seaweedfs: + <<: *restart_policy + image: "chrislusf/seaweedfs:3.96_large_disk" + entrypoint: "weed" + command: >- + server + -filer=true + -filer.port=8888 + -filer.port.grpc=18888 + -filer.defaultReplicaPlacement=000 + -master=true + -master.port=9333 + -master.port.grpc=19333 + -metricsPort=9091 + -s3=true + -s3.port=8333 + -s3.port.grpc=18333 + -volume=true + -volume.dir.idx=/data/idx + -volume.index=leveldbLarge + -volume.max=0 + -volume.preStopSeconds=8 + -volume.readMode=redirect + -volume.port=8080 + -volume.port.grpc=18080 + -ip=127.0.0.1 + -ip.bind=0.0.0.0 + -webdav=false + environment: + AWS_ACCESS_KEY_ID: sentry + AWS_SECRET_ACCESS_KEY: sentry + volumes: + - "sentry-seaweedfs:/data" + healthcheck: + test: ["CMD", "wget", "-q", "-O-", "http://seaweedfs:8080/healthz", "http://seaweedfs:9333/cluster/healthz", "http://seaweedfs:8333/healthz"] + interval: 30s + timeout: 20s + retries: 5 + start_period: 60s snuba-api: <<: *snuba_defaults healthcheck: @@ -801,6 +842,8 @@ volumes: external: true sentry-symbolicator: external: true + sentry-seaweedfs: + external: true # This volume stores JS SDK assets and the data inside this volume should # be cleaned periodically on upgrades. sentry-nginx-www: diff --git a/install.sh b/install.sh index d7f8a036f4e..c6b3a62a178 100755 --- a/install.sh +++ b/install.sh @@ -36,6 +36,7 @@ source install/ensure-relay-credentials.sh source install/generate-secret-key.sh source install/update-docker-images.sh source install/build-docker-images.sh +source install/bootstrap-s3-nodestore.sh source install/bootstrap-snuba.sh source install/upgrade-postgres.sh source install/ensure-correct-permissions-profiles-dir.sh diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh new file mode 100644 index 00000000000..bf767a78295 --- /dev/null +++ b/install/bootstrap-s3-nodestore.sh @@ -0,0 +1,91 @@ +echo "${_group}Bootstrapping seaweedfs (node store)..." + +$dc up --wait seaweedfs postgres +$dc exec seaweedfs apk add --no-cache s3cmd +$dc exec seaweedfs mkdir -p /data/idx/ +s3cmd="$dc exec seaweedfs s3cmd" + +bucket_list=$($s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' ls) + +if [[ $($bucket_list | tail -1 | awk '{print $3}') != 's3://nodestore' ]]; then + apply_config_changes_nodestore=0 + # Only touch if no existing nodestore config is found + if ! grep -q "SENTRY_NODESTORE" $SENTRY_CONFIG_PY; then + if [[ -z "${APPLY_AUTOMATIC_CONFIG_UPDATES:-}" ]]; then + echo + echo "We want to migrate Nodestore backend from Postgres to S3 which will" + echo "help reducing Postgres storage issues. In order to do that, we need" + echo "to modify your sentry.conf.py file contents." + echo "Do you want us to do it automatically for you?" + echo + + yn="" + until [ ! -z "$yn" ]; do + read -p "y or n? " yn + case $yn in + y | yes | 1) + export apply_config_changes_nodestore=1 + echo + echo -n "Thank you." + ;; + n | no | 0) + export apply_config_changes_nodestore=0 + echo + echo -n "Alright, you will need to update your sentry.conf.py file manually before running 'docker compose up'." + ;; + *) yn="" ;; + esac + done + + echo + echo "To avoid this prompt in the future, use one of these flags:" + echo + echo " --apply-automatic-config-updates" + echo " --no-apply-automatic-config-updates" + echo + echo "or set the APPLY_AUTOMATIC_CONFIG_UPDATES environment variable:" + echo + echo " APPLY_AUTOMATIC_CONFIG_UPDATES=1 to apply automatic updates" + echo " APPLY_AUTOMATIC_CONFIG_UPDATES=0 to not apply automatic updates" + echo + sleep 5 + fi + + if [[ "$APPLY_AUTOMATIC_CONFIG_UPDATES" == 1 || "$apply_config_changes_nodestore" == 1 ]]; then + nodestore_config=$(sed -n '/SENTRY_NODESTORE/,/[}]/{p}' sentry/sentry.conf.example.py) + if [[ $($dc exec postgres psql -qAt -U postgres -c "select exists (select * from nodestore_node limit 1)") = "f" ]]; then + nodestore_config=$(echo -e "$nodestore_config" | sed '$s/\}/ "read_through": True,\n "delete_through": True,\n\}/') + fi + echo "$nodestore_config" >>$SENTRY_CONFIG_PY + fi + fi + + $dc exec seaweedfs mkdir -p /data/idx/ + $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' mb s3://nodestore + + # XXX(aldy505): Should we refactor this? + lifecycle_policy=$( + cat < + + + Sentry-Nodestore-Rule + Enabled + + + $SENTRY_EVENT_RETENTION_DAYS + + + +EOF + ) + $dc exec seaweedfs sh -c "printf '%s' '$lifecycle_policy' > /tmp/nodestore-lifecycle-policy.xml" + $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' setlifecycle /tmp/nodestore-lifecycle-policy.xml s3://nodestore + + echo "Making sure the bucket lifecycle policy is all set up correctly..." + $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' getlifecycle s3://nodestore +else + echo "Node store already exists, skipping..." +fi + +echo "${_endgroup}" diff --git a/install/create-docker-volumes.sh b/install/create-docker-volumes.sh index fdbecc2288b..c0437c5563b 100644 --- a/install/create-docker-volumes.sh +++ b/install/create-docker-volumes.sh @@ -17,5 +17,6 @@ echo "Created $(create_volume sentry-kafka)." echo "Created $(create_volume sentry-postgres)." echo "Created $(create_volume sentry-redis)." echo "Created $(create_volume sentry-symbolicator)." +echo "Created $(create_volume sentry-seaweedfs)." echo "${_endgroup}" diff --git a/sentry/Dockerfile b/sentry/Dockerfile index 557046f143d..40398a773fb 100644 --- a/sentry/Dockerfile +++ b/sentry/Dockerfile @@ -1,13 +1,15 @@ ARG SENTRY_IMAGE FROM ${SENTRY_IMAGE} +RUN pip install https://github.com/stayallive/sentry-nodestore-s3/archive/main.zip + COPY . /usr/src/sentry RUN if [ -s /usr/src/sentry/enhance-image.sh ]; then \ /usr/src/sentry/enhance-image.sh; \ -fi + fi RUN if [ -s /usr/src/sentry/requirements.txt ]; then \ echo "sentry/requirements.txt is deprecated, use sentry/enhance-image.sh - see https://develop.sentry.dev/self-hosted/#enhance-sentry-image"; \ pip install -r /usr/src/sentry/requirements.txt; \ -fi + fi diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 7fef845fb5d..9419e6a74e3 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -95,6 +95,31 @@ def get_internal_network(): # See https://develop.sentry.dev/self-hosted/experimental/errors-only/ SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" +################ +# Node Storage # +################ + +# Sentry uses an abstraction layer called "node storage" to store raw events. +# Previously, it used PostgreSQL as the backend, but this didn't scale for +# high-throughput environments. Read more about this in the documentation: +# https://develop.sentry.dev/backend/application-domains/nodestore/ +# +# Through this setting, you can use the provided blob storage or +# your own S3-compatible API from your infrastructure. +# Other backend implementations for node storage developed by the community +# are available in public GitHub repositories. + +SENTRY_NODESTORE = "sentry_nodestore_s3.S3PassthroughDjangoNodeStorage" +SENTRY_NODESTORE_OPTIONS = { + "compression": True, + "endpoint_url": "http://seaweedfs:8333", + "bucket_path": "nodestore", + "bucket_name": "nodestore", + "region_name": "us-east-1", + "aws_access_key_id": "sentry", + "aws_secret_access_key": "sentry", +} + ######### # Redis # ######### From b091611020a826441e536589b7619d8c84910c91 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 15 Sep 2025 13:11:25 +0700 Subject: [PATCH 243/305] docs: provide information for SENTRY_AIR_GAP flag on Django config file (#3935) * docs: provide information for SENTRY_AIR_GAP flag on Django config file * Apply suggestions from code review Co-authored-by: Amin Vakil * Apply suggestions from code review Co-authored-by: Amin Vakil --------- Co-authored-by: Amin Vakil --- sentry/sentry.conf.example.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 9419e6a74e3..f6ef319f6bc 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -95,6 +95,14 @@ def get_internal_network(): # See https://develop.sentry.dev/self-hosted/experimental/errors-only/ SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" +# When running in an air-gapped environment, set this to True to entirely disable +# external network calls and features that require Internet connectivity. +# +# Setting the value to False while running in an air-gapped environment will +# cause some containers to raise exceptions. One known example is fetching +# AI model prices from various public APIs. +SENTRY_AIR_GAP = False + ################ # Node Storage # ################ From 407351fb0706a61d20fcbc5d682260f5bbd13267 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:39:10 +0100 Subject: [PATCH 244/305] build(deps): bump actions/create-github-app-token from 2.1.1 to 2.1.4 (#3936) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.1.1 to 2.1.4. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/a8d616148505b5069dccd32f177bb87d7f39123b...67018539274d69449ef7c02e8e71183d1719ab42) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 2.1.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bbd7dfd659f..d4bacd7aed1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b # v2.1.1 + uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From a222e3f8de7cc5881c78fb8722384280995e29d3 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 16 Sep 2025 22:01:13 +0700 Subject: [PATCH 245/305] fix: able to setup nodestore multiple times (#3940) * fix: able to setup nodestore multiple times * fix(test): chmod issues --- _unit-test/bootstrap-s3-seaweed-test.sh | 16 ++++++++++++++++ install/bootstrap-s3-nodestore.sh | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100755 _unit-test/bootstrap-s3-seaweed-test.sh diff --git a/_unit-test/bootstrap-s3-seaweed-test.sh b/_unit-test/bootstrap-s3-seaweed-test.sh new file mode 100755 index 00000000000..2bd052f04c8 --- /dev/null +++ b/_unit-test/bootstrap-s3-seaweed-test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +source _unit-test/_test_setup.sh +source install/dc-detect-version.sh +source install/create-docker-volumes.sh + +# Set the flag to apply automatic updates +export APPLY_AUTOMATIC_CONFIG_UPDATES=1 + +# Here we're just gonna test to run it multiple times +# Only to make sure it doesn't break +for i in $(seq 1 5); do + source install/bootstrap-s3-nodestore.sh +done + +report_success diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh index bf767a78295..a41fab48c54 100644 --- a/install/bootstrap-s3-nodestore.sh +++ b/install/bootstrap-s3-nodestore.sh @@ -7,7 +7,7 @@ s3cmd="$dc exec seaweedfs s3cmd" bucket_list=$($s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' ls) -if [[ $($bucket_list | tail -1 | awk '{print $3}') != 's3://nodestore' ]]; then +if [[ $(echo "$bucket_list" | tail -1 | awk '{print $3}') != 's3://nodestore' ]]; then apply_config_changes_nodestore=0 # Only touch if no existing nodestore config is found if ! grep -q "SENTRY_NODESTORE" $SENTRY_CONFIG_PY; then From 867004274e8a08560445ea41d5c400bfb3ff4443 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 16 Sep 2025 15:15:39 +0000 Subject: [PATCH 246/305] release: 25.9.0 --- .env | 14 +++++++------- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/.env b/.env index dfe279267f8..a7991959890 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly -SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly -RELAY_IMAGE=ghcr.io/getsentry/relay:nightly -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly -VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.9.0 +SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.9.0 +RELAY_IMAGE=ghcr.io/getsentry/relay:25.9.0 +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.9.0 +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.9.0 +VROOM_IMAGE=ghcr.io/getsentry/vroom:25.9.0 +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.9.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 88a8d4528f7..3e1944842e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## 25.9.0 + +### Various fixes & improvements + +- fix: able to setup nodestore multiple times (#3940) by @aldy505 +- build(deps): bump actions/create-github-app-token from 2.1.1 to 2.1.4 (#3936) by @dependabot +- docs: provide information for SENTRY_AIR_GAP flag on Django config file (#3935) by @aldy505 +- feat: Use S3 node store with seaweedfs (#3498) by @BYK +- feat(tasks): Remove taskworker option override and add worker healthcheck (#3933) by @markstory +- feat: install script to migrate sentry.conf.py config to use pgbouncer (#3898) by @aldy505 +- chore(deps): bump clickhouse to 25.3 (#3878) by @aldy505 +- feat: enable `issue-views` flag (#3922) by @aldy505 +- feat: query against `eap` dataset instead of `metrics` dataset for spans (#3923) by @aldy505 +- build(deps): bump actions/setup-python from 5 to 6 (#3927) by @dependabot +- Add restart policy to pgbouncer service (#3925) by @frederikspang +- fix(tests): skip logs event test for errors-only (#3915) by @aldy505 +- Improve nginx depends_on policy (#3914) by @aminvakil +- test: run errors-only integration tests (#3910) by @aldy505 +- feat: enable Logs feature (#3912) by @aldy505 +- fix: ensuring vroom permission should be skipped on errors-only (#3911) by @aldy505 +- chore(deps): bump patches version (#3879) by @aldy505 +- Revert "increase postgres max_connections above 100 connections (#2740)" (#3899) by @aminvakil +- Add pgbouncer (#3884) by @frederikspang +- chore: resolve GHA code scanning alerts (#3889) by @aldy505 +- fix(enhancement): search for permissions on docker container instead of host and combine it in one command for performance enhancement (#3890) by @LvckyAPI +- build(deps): bump actions/create-github-app-token from 2.1.0 to 2.1.1 (#3885) by @dependabot +- build(deps): bump actions/checkout from 4 to 5 (#3883) by @dependabot + ## 25.8.0 ### Various fixes & improvements From ec44e9881304449dfaa3253345f153a7454ebcd2 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 17 Sep 2025 14:42:18 +0000 Subject: [PATCH 247/305] build: Set master version to nightly #skip-changelog --- .env | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env b/.env index a7991959890..dfe279267f8 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.9.0 -SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.9.0 -RELAY_IMAGE=ghcr.io/getsentry/relay:25.9.0 -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.9.0 -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.9.0 -VROOM_IMAGE=ghcr.io/getsentry/vroom:25.9.0 -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.9.0 +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 8fc3efac78c401db91989eefa05c6dcdd7785f72 Mon Sep 17 00:00:00 2001 From: Moroine Bentefrit Date: Fri, 19 Sep 2025 14:07:51 +0000 Subject: [PATCH 248/305] fix: install behind a proxy (#3944) Updated the s3cmd installation command to include proxy environment variables. --- install/bootstrap-s3-nodestore.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh index a41fab48c54..15aec23c71e 100644 --- a/install/bootstrap-s3-nodestore.sh +++ b/install/bootstrap-s3-nodestore.sh @@ -1,7 +1,7 @@ echo "${_group}Bootstrapping seaweedfs (node store)..." $dc up --wait seaweedfs postgres -$dc exec seaweedfs apk add --no-cache s3cmd +$dc exec -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" seaweedfs apk add --no-cache s3cmd $dc exec seaweedfs mkdir -p /data/idx/ s3cmd="$dc exec seaweedfs s3cmd" From b4723a0c6f76564c5151646450d628cd5d585f92 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 19 Sep 2025 10:47:41 -0400 Subject: [PATCH 249/305] chore(tasks): Remove the worker and cron containers (#3946) These are replaced by the `taskworker` and `taskscheduler` containers Refs STREAM-433 --- docker-compose.yml | 14 -------------- sentry/sentry.conf.example.py | 19 ------------------- 2 files changed, 33 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 47f0b31844c..319e4be5bf8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -512,20 +512,6 @@ services: - "-c" # Courtesy of https://unix.stackexchange.com/a/234089/108960 - 'exec 3<>/dev/tcp/127.0.0.1/9000 && echo -e "GET /_health/ HTTP/1.1\r\nhost: 127.0.0.1\r\n\r\n" >&3 && grep ok -s -m 1 <&3' - cron: - <<: *sentry_defaults - command: run cron - worker: - <<: *sentry_defaults - command: run worker - healthcheck: - <<: *healthcheck_defaults - test: - - CMD - - sentry - - exec - - -c - - 'from sentry.celery import app; import os; dest="celery@{}".format(os.environ["HOSTNAME"]); print(app.control.ping(destination=[dest], timeout=5)[0][dest]["ok"])' events-consumer: <<: *sentry_defaults command: run consumer ingest-events --consumer-group ingest-consumer --healthcheck-file-path /tmp/health.txt diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index f6ef319f6bc..38147f7bb02 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -141,25 +141,6 @@ def get_internal_network(): } } -######### -# Queue # -######### - -# See https://develop.sentry.dev/services/queue/ for more -# information on configuring your queue broker and workers. Sentry relies -# on a Python framework called Celery to manage queues. - -rabbitmq_host = None -if rabbitmq_host: - BROKER_URL = "amqp://{username}:{password}@{host}/{vhost}".format( - username="guest", password="guest", host=rabbitmq_host, vhost="/" - ) -else: - BROKER_URL = "redis://:{password}@{host}:{port}/{db}".format( - **SENTRY_OPTIONS["redis.clusters"]["default"]["hosts"][0] - ) - - ######### # Cache # ######### From 18b7a4d1cccbdbd6b7d278761383160e305e0765 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Tue, 23 Sep 2025 17:31:30 +0330 Subject: [PATCH 250/305] Respect uppercase proxy variables (#3949) * Respect uppercase proxy variables * Put http_proxy first --- cron/Dockerfile | 2 ++ docker-compose.yml | 2 +- install/bootstrap-s3-nodestore.sh | 2 +- install/dc-detect-version.sh | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cron/Dockerfile b/cron/Dockerfile index c14304eb89a..26c46a6f68f 100644 --- a/cron/Dockerfile +++ b/cron/Dockerfile @@ -1,6 +1,8 @@ ARG BASE_IMAGE FROM ${BASE_IMAGE} USER 0 +RUN if [ -n "${HTTP_PROXY}" ]; then echo "Acquire::http::proxy \"${HTTP_PROXY}\";" >> /etc/apt/apt.conf; fi +RUN if [ -n "${HTTPS_PROXY}" ]; then echo "Acquire::https::proxy \"${HTTPS_PROXY}\";" >> /etc/apt/apt.conf; fi RUN if [ -n "${http_proxy}" ]; then echo "Acquire::http::proxy \"${http_proxy}\";" >> /etc/apt/apt.conf; fi RUN if [ -n "${https_proxy}" ]; then echo "Acquire::https::proxy \"${https_proxy}\";" >> /etc/apt/apt.conf; fi RUN apt-get update && apt-get install -y --no-install-recommends cron && \ diff --git a/docker-compose.yml b/docker-compose.yml index 319e4be5bf8..2c3cd9264e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -235,7 +235,7 @@ services: # Manually override any http_proxy envvar that might be set, because # this wget does not support no_proxy. See: # https://github.com/getsentry/self-hosted/issues/1537 - "http_proxy='' wget -nv -t1 --spider 'http://localhost:8123/' || exit 1", + "HTTP_PROXY='' http_proxy='' wget -nv -t1 --spider 'http://localhost:8123/' || exit 1", ] interval: 10s timeout: 10s diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh index 15aec23c71e..fb88c2e4786 100644 --- a/install/bootstrap-s3-nodestore.sh +++ b/install/bootstrap-s3-nodestore.sh @@ -1,7 +1,7 @@ echo "${_group}Bootstrapping seaweedfs (node store)..." $dc up --wait seaweedfs postgres -$dc exec -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" seaweedfs apk add --no-cache s3cmd +$dc exec -e "HTTP_PROXY=${HTTP_PROXY:-}" -e "HTTPS_PROXY=${HTTPS_PROXY:-}" -e "NO_PROXY=${NO_PROXY:-}" -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" seaweedfs apk add --no-cache s3cmd $dc exec seaweedfs mkdir -p /data/idx/ s3cmd="$dc exec seaweedfs s3cmd" diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index 6f9d4230d77..f7a4cbdda97 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -47,9 +47,9 @@ else dc="$dc_base $NO_ANSI" fi -proxy_args="--build-arg http_proxy=${http_proxy:-} --build-arg https_proxy=${https_proxy:-} --build-arg no_proxy=${no_proxy:-}" +proxy_args="--build-arg HTTP_PROXY=${HTTP_PROXY:-} --build-arg HTTPS_PROXY=${HTTPS_PROXY:-} --build-arg NO_PROXY=${NO_PROXY:-} --build-arg http_proxy=${http_proxy:-} --build-arg https_proxy=${https_proxy:-} --build-arg no_proxy=${no_proxy:-}" if [[ "$CONTAINER_ENGINE" == "podman" ]]; then - proxy_args_dc="--podman-build-args http_proxy=${http_proxy:-},https_proxy=${https_proxy:-},no_proxy=${no_proxy:-}" + proxy_args_dc="--podman-build-args HTTP_PROXY=${HTTP_PROXY:-},HTTPS_PROXY=${HTTPS_PROXY:-},NO_PROXY=${NO_PROXY:-},http_proxy=${http_proxy:-},https_proxy=${https_proxy:-},no_proxy=${no_proxy:-}" # Disable pod creation as these are one-off commands and creating a pod # prints its pod id to stdout which is messing with the output that we # rely on various places such as configuration generation From 0ffcf0e1269e0995949cc04e3154d02430f3b6ff Mon Sep 17 00:00:00 2001 From: Mark Story Date: Wed, 24 Sep 2025 19:44:49 -0400 Subject: [PATCH 251/305] chore(tasks) Remove reference to celery (#3962) --- install/_lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/_lib.sh b/install/_lib.sh index 3beb18e38db..29097049576 100644 --- a/install/_lib.sh +++ b/install/_lib.sh @@ -53,7 +53,7 @@ export SENTRY_CONFIG_PY=sentry/sentry.conf.py export SENTRY_CONFIG_YML=sentry/config.yml # Increase the default 10 second SIGTERM timeout -# to ensure celery queues are properly drained +# to ensure task queues are properly drained # between upgrades as task signatures may change across # versions export STOP_TIMEOUT=60 # seconds From 37918fb464176249c1f77440f767aa2fc9371df0 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Fri, 26 Sep 2025 17:25:35 +0330 Subject: [PATCH 252/305] Fix swap allocation in integration test (#3972) * Check free space prior to offing swap * Get hint about packages disk usage * Comment self-hosted installation to speed up * Revert "Comment self-hosted installation to speed up" This reverts commit 257e57f9d067ec14dc1b04df9d53a91514aa96d1. * Comment self-hosted installation * Revert "Comment self-hosted installation" This reverts commit f22beff1e57bc305548c1bfafbb73e4f049ccf5b. * Revert "Get hint about packages disk usage" This reverts commit f4fd43c31db469d5a89b2615440d1577dfd0a5eb. * Remove jdk packages and their depended ons * Remove man-db * Remove microsoft packages * Remove php packages * Cleanup runner image prior to everything * Remove all *jre* packages * Remove jdk packages more aggressively * Remove haskell directory * Remove df -h commands --- action.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/action.yaml b/action.yaml index 563e06d40d6..a41f453336a 100644 --- a/action.yaml +++ b/action.yaml @@ -42,6 +42,12 @@ runs: echo "COMPOSE_PROFILES=$COMPOSE_PROFILES" >> ${{ github.action_path }}/.env fi + - name: Cleanup runner image + shell: bash + run: | + ### Inspired by https://github.com/endersonmenezes/free-disk-space ### + sudo rm -rf /usr/local/.ghcup + - name: Setup dev environment shell: bash run: | From 2d11de51e57be9232c4e3c5e5943a9551d99d25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemens=20B=C3=B6swirth?= <23529132+kodebach@users.noreply.github.com> Date: Fri, 26 Sep 2025 16:13:59 +0200 Subject: [PATCH 253/305] fix: logic error in s3 install script (#3965) --- install/bootstrap-s3-nodestore.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh index fb88c2e4786..c2cf91669f5 100644 --- a/install/bootstrap-s3-nodestore.sh +++ b/install/bootstrap-s3-nodestore.sh @@ -53,7 +53,7 @@ if [[ $(echo "$bucket_list" | tail -1 | awk '{print $3}') != 's3://nodestore' ]] if [[ "$APPLY_AUTOMATIC_CONFIG_UPDATES" == 1 || "$apply_config_changes_nodestore" == 1 ]]; then nodestore_config=$(sed -n '/SENTRY_NODESTORE/,/[}]/{p}' sentry/sentry.conf.example.py) - if [[ $($dc exec postgres psql -qAt -U postgres -c "select exists (select * from nodestore_node limit 1)") = "f" ]]; then + if [[ $($dc exec postgres psql -qAt -U postgres -c "select exists (select * from nodestore_node limit 1)") = "t" ]]; then nodestore_config=$(echo -e "$nodestore_config" | sed '$s/\}/ "read_through": True,\n "delete_through": True,\n\}/') fi echo "$nodestore_config" >>$SENTRY_CONFIG_PY From 1640300332428e0d7d8afe74b75333e37886e346 Mon Sep 17 00:00:00 2001 From: Javan Eskander Date: Sat, 27 Sep 2025 00:16:45 +1000 Subject: [PATCH 254/305] fix: Unset the proxy when performing the seaweedfs health check (#3959) --- docker-compose.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2c3cd9264e3..4c72da11d52 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -274,7 +274,13 @@ services: volumes: - "sentry-seaweedfs:/data" healthcheck: - test: ["CMD", "wget", "-q", "-O-", "http://seaweedfs:8080/healthz", "http://seaweedfs:9333/cluster/healthz", "http://seaweedfs:8333/healthz"] + test: [ + "CMD-SHELL", + # Manually override any http_proxy envvar that might be set, because + # this wget does not support no_proxy. See: + # https://github.com/getsentry/self-hosted/issues/1537 + "http_proxy='' wget -q -O- http://seaweedfs:8080/healthz http://seaweedfs:9333/cluster/healthz http://seaweedfs:8333/healthz || exit 1", + ] interval: 30s timeout: 20s retries: 5 From 663b86c108e4bb690987361c65e7e182bee45ce6 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Fri, 26 Sep 2025 18:15:09 +0330 Subject: [PATCH 255/305] ref: Remove proxy_next_upstream directives (#3973) --- nginx.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/nginx.conf b/nginx.conf index 94d7964d58d..95e96226c1c 100644 --- a/nginx.conf +++ b/nginx.conf @@ -41,8 +41,6 @@ http { proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; - proxy_next_upstream error timeout invalid_header http_502 http_503 non_idempotent; - proxy_next_upstream_tries 2; # Docker default address pools # https://github.com/moby/libnetwork/blob/3797618f9a38372e8107d8c06f6ae199e1133ae8/ipamutils/utils.go#L10-L22 From 79b46fb495e2ce24a902e6bbc1eb14187162613b Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 26 Sep 2025 23:16:52 +0700 Subject: [PATCH 256/305] fix(actions): include arch and compose_profiles information on cache keys (#3974) Closes #3964 --------- Co-authored-by: Burak Yigit Kaya --- action.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/action.yaml b/action.yaml index a41f453336a..6b254f2d771 100644 --- a/action.yaml +++ b/action.yaml @@ -80,14 +80,15 @@ runs: echo "SENTRY_MIGRATIONS_MD5=$SENTRY_MIGRATIONS_MD5" >> $GITHUB_OUTPUT SNUBA_MIGRATIONS_MD5=$(docker run --rm --entrypoint bash $SNUBA_IMAGE -c '{ ls -Rv1rpq snuba/snuba_migrations/**/*.py; grep -Poz "(?s)(?<=class Topic\\(Enum\\):\\n).+?(?=\\n\\n\\n)" snuba/utils/streams/topics.py; }' | md5sum | cut -d ' ' -f 1) echo "SNUBA_MIGRATIONS_MD5=$SNUBA_MIGRATIONS_MD5" >> $GITHUB_OUTPUT + echo "ARCH=$(uname -m)" >> $GITHUB_OUTPUT - name: Restore Sentry Volume Cache id: restore_cache_sentry uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-sentry-v2-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} + key: db-volumes-sentry-v3-${{ steps.cache_key.outputs.ARCH }}-${{ inputs.compose_profiles }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} restore-keys: | - db-volumes-sentry-v1- + key: db-volumes-sentry-v3-${{ steps.cache_key.outputs.ARCH }}-${{ inputs.compose_profiles }} volumes: | sentry-postgres @@ -95,9 +96,9 @@ runs: id: restore_cache_snuba uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-snuba-v2-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + key: db-volumes-snuba-v3-${{ steps.cache_key.outputs.ARCH }}-${{ inputs.compose_profiles }}-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} restore-keys: | - db-volumes-snuba-v1- + key: db-volumes-snuba-v3-${{ steps.cache_key.outputs.ARCH }}-${{ inputs.compose_profiles }} volumes: | sentry-clickhouse @@ -105,11 +106,10 @@ runs: id: restore_cache_kafka uses: BYK/docker-volume-cache-action/restore@be89365902126f508dcae387a32ec3712df6b1cd with: - key: db-volumes-kafka-v1-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} + key: db-volumes-kafka-v2-${{ steps.cache_key.outputs.ARCH }}-${{ inputs.compose_profiles }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} restore-keys: | - db-volumes-kafka-v1-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }}-${{ steps.cache_key.outputs.SNUBA_MIGRATIONS_MD5 }} - db-volumes-kafka-v1-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }}- - db-volumes-kafka-v1- + db-volumes-kafka-v2-${{ steps.cache_key.outputs.ARCH }}-${{ inputs.compose_profiles }}-${{ steps.cache_key.outputs.SENTRY_MIGRATIONS_MD5 }} + db-volumes-kafka-v2-${{ steps.cache_key.outputs.ARCH }}-${{ inputs.compose_profiles }} volumes: | sentry-kafka From 143f58579f29d2ceb8969299b9a67aec53390549 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 1 Oct 2025 16:14:32 +0700 Subject: [PATCH 257/305] ref: use dedicated `healthcheck` command for symbolicator & remove cron for `symbolicator-cleanup` (#3979) --- docker-compose.yml | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4c72da11d52..321072cf035 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -479,6 +479,7 @@ services: symbolicator: <<: *restart_policy image: "$SYMBOLICATOR_IMAGE" + command: run -c /etc/symbolicator/config.yml volumes: - "sentry-symbolicator:/data" - type: bind @@ -487,23 +488,17 @@ services: target: /etc/symbolicator healthcheck: <<: *healthcheck_defaults - test: - - "CMD" - - "/bin/bash" - - "-c" - # Courtesy of https://unix.stackexchange.com/a/234089/108960 - - 'exec 3<>/dev/tcp/127.0.0.1/3021 && echo -e "GET /healthcheck HTTP/1.1\r\nhost: 127.0.0.1\r\nConnection: close\r\n\r\n" >&3 && grep OK -s -m 1 <&3' - command: run -c /etc/symbolicator/config.yml + test: ["CMD", "/bin/symbolicator", "healthcheck", "-c", "/etc/symbolicator/config.yml"] symbolicator-cleanup: - <<: [*restart_policy, *pull_policy] - image: symbolicator-cleanup-self-hosted-local - build: - context: ./cron - args: - BASE_IMAGE: "$SYMBOLICATOR_IMAGE" - command: '"55 23 * * * gosu symbolicator symbolicator cleanup"' + <<: *restart_policy + image: "$SYMBOLICATOR_IMAGE" + command: "cleanup -c /etc/symbolicator/config.yml --repeat 1h" volumes: - "sentry-symbolicator:/data" + - type: bind + read_only: true + source: ./symbolicator + target: /etc/symbolicator web: <<: *sentry_defaults ulimits: From 5cf07c888887516918f5c17810e8f7bae5ac7a4a Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 1 Oct 2025 16:54:00 +0700 Subject: [PATCH 258/305] ref: add `continue-on-error` for codecov action on self-hosted integration tests (#3978) --- action.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 6b254f2d771..7f7a98f84fc 100644 --- a/action.yaml +++ b/action.yaml @@ -186,8 +186,9 @@ runs: pytest -x --cov --junitxml=junit.xml _integration-test/ - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 if: inputs.CODECOV_TOKEN + continue-on-error: true + uses: codecov/codecov-action@v5 with: directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} @@ -195,6 +196,7 @@ runs: - name: Upload test results to Codecov if: inputs.CODECOV_TOKEN && !cancelled() + continue-on-error: true uses: codecov/test-results-action@v1 with: directory: ${{ github.action_path }} From 0ed356938badadaff3b1a08b423ae2876639d1d6 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Wed, 8 Oct 2025 00:50:07 +0330 Subject: [PATCH 259/305] Bump redis 6.2.20-alpine (#3988) https://redis.io/blog/security-advisory-cve-2025-49844/ --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 321072cf035..fdb4f8c7914 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -117,7 +117,7 @@ services: test: echo stats | nc 127.0.0.1 11211 redis: <<: *restart_policy - image: "redis:6.2.19-alpine" + image: "redis:6.2.20-alpine" healthcheck: <<: *healthcheck_defaults test: redis-cli ping | grep PONG From b77c5a809722bf41bdcdbdef8dfdbc759d6cc90b Mon Sep 17 00:00:00 2001 From: Joris Bayer Date: Thu, 9 Oct 2025 13:43:40 +0200 Subject: [PATCH 260/305] chore(spans): Remove old snuba-spans consumer (#3989) --- docker-compose.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index fdb4f8c7914..64781e6675d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -450,13 +450,6 @@ services: <<: *file_healthcheck_defaults profiles: - feature-complete - snuba-spans-consumer: - <<: *snuba_defaults - command: rust-consumer --storage spans --consumer-group snuba-spans-consumers --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --health-check-file /tmp/health.txt - healthcheck: - <<: *file_healthcheck_defaults - profiles: - - feature-complete snuba-eap-items-consumer: <<: *snuba_defaults command: rust-consumer --storage eap_items --consumer-group eap_items_group --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset --use-rust-processor --health-check-file /tmp/health.txt From e1f003313e829fb662a8f8845da90275f297f1c5 Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Fri, 10 Oct 2025 05:44:41 +0330 Subject: [PATCH 261/305] Remove symbolicator external volume (#3992) * Remove symbolicator volume creation command * Remove symbolicator volume * Create sentry-symbolicator on docker compose up * Pass volume name to remove_command * Remove sentry-symbolicator from unit test --- _unit-test/create-docker-volumes-test.sh | 3 +-- docker-compose.yml | 5 +++-- install/create-docker-volumes.sh | 1 - install/turn-things-off.sh | 7 +++++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/_unit-test/create-docker-volumes-test.sh b/_unit-test/create-docker-volumes-test.sh index 83591d3aa85..5de88e420f7 100755 --- a/_unit-test/create-docker-volumes-test.sh +++ b/_unit-test/create-docker-volumes-test.sh @@ -14,8 +14,7 @@ sentry-data sentry-kafka sentry-postgres sentry-redis -sentry-seaweedfs -sentry-symbolicator" +sentry-seaweedfs" before=$(get_volumes) diff --git a/docker-compose.yml b/docker-compose.yml index 64781e6675d..f53c3c3a8ee 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -820,10 +820,11 @@ volumes: external: true sentry-clickhouse: external: true - sentry-symbolicator: - external: true sentry-seaweedfs: external: true + # The volume stores cached version of debug symbols, source maps etc. Upon + # removal symbolicator will re-download them. + sentry-symbolicator: # This volume stores JS SDK assets and the data inside this volume should # be cleaned periodically on upgrades. sentry-nginx-www: diff --git a/install/create-docker-volumes.sh b/install/create-docker-volumes.sh index c0437c5563b..9241caa0e1b 100644 --- a/install/create-docker-volumes.sh +++ b/install/create-docker-volumes.sh @@ -16,7 +16,6 @@ echo "Created $(create_volume sentry-data)." echo "Created $(create_volume sentry-kafka)." echo "Created $(create_volume sentry-postgres)." echo "Created $(create_volume sentry-redis)." -echo "Created $(create_volume sentry-symbolicator)." echo "Created $(create_volume sentry-seaweedfs)." echo "${_endgroup}" diff --git a/install/turn-things-off.sh b/install/turn-things-off.sh index 1c70ce392c8..576220665ca 100644 --- a/install/turn-things-off.sh +++ b/install/turn-things-off.sh @@ -17,4 +17,11 @@ else fi fi +remove_volume() { + remove_command="$CONTAINER_ENGINE volume remove -f" + $remove_command $1 +} + +echo "Removed $(remove_volume sentry-symbolicator)." + echo "${_endgroup}" From da1f546bfb37c5f3962f956908a10192170199fa Mon Sep 17 00:00:00 2001 From: Amin Vakil Date: Sat, 11 Oct 2025 03:37:40 +0330 Subject: [PATCH 262/305] Remove symbolicator volume once (#3994) * Remove sentry-symbolicator only if it exists * Remove unnecessary volume remove force flag --- install/turn-things-off.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/install/turn-things-off.sh b/install/turn-things-off.sh index 576220665ca..fc0ddf38d48 100644 --- a/install/turn-things-off.sh +++ b/install/turn-things-off.sh @@ -17,11 +17,16 @@ else fi fi +exists_volume() { + $CONTAINER_ENGINE volume inspect $1 >&/dev/null +} remove_volume() { - remove_command="$CONTAINER_ENGINE volume remove -f" + remove_command="$CONTAINER_ENGINE volume remove" $remove_command $1 } -echo "Removed $(remove_volume sentry-symbolicator)." +if exists_volume sentry-symbolicator; then + echo "Removed $(remove_volume sentry-symbolicator)." +fi echo "${_endgroup}" From c55b93bfa12ee9c551ad141a15ee15a9e3c0c2d2 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 15 Oct 2025 05:01:10 +0700 Subject: [PATCH 263/305] fix: missing `-dir` flag for seaweedfs (#3991) --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index f53c3c3a8ee..e7400ae61a3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -246,6 +246,7 @@ services: entrypoint: "weed" command: >- server + -dir=/data -filer=true -filer.port=8888 -filer.port.grpc=18888 From 60da8f6eb00f41024f3b13356034023777f8c982 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 15 Oct 2025 20:31:03 +0700 Subject: [PATCH 264/305] fix: geoip standalone script should check on CONTAINER_ENGINE variable first (#3982) --- install/geoip.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/install/geoip.sh b/install/geoip.sh index 0d1b2efc0aa..9cea3082409 100644 --- a/install/geoip.sh +++ b/install/geoip.sh @@ -1,5 +1,18 @@ echo "${_group}Setting up GeoIP integration ..." +# If `$CONTAINER_ENGINE` is not set, we assume that we are running this script independently +# to update the geoip database as written on the documentation. +# Therefore we need to `source _detect-container-engine.sh` to detect the container engine. +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P) +if [[ -z "$CONTAINER_ENGINE" ]]; then + if [[ -f "$script_dir/_detect-container-engine.sh" ]]; then + source $script_dir/_detect-container-engine.sh + else + echo "Error: Cannot find _detect-container-engine.sh. Defaulting to docker." + export CONTAINER_ENGINE="docker" + fi +fi + install_geoip() { local mmdb=geoip/GeoLite2-City.mmdb local conf=geoip/GeoIP.conf From 77a33346db67a07bf5de1ee8eabed23e8622976b Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 15 Oct 2025 18:07:56 +0000 Subject: [PATCH 265/305] release: 25.10.0 --- .env | 14 +++++++------- CHANGELOG.md | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/.env b/.env index dfe279267f8..5d2bae9abc6 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly -SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly -RELAY_IMAGE=ghcr.io/getsentry/relay:nightly -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly -VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.10.0 +SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.10.0 +RELAY_IMAGE=ghcr.io/getsentry/relay:25.10.0 +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.10.0 +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.10.0 +VROOM_IMAGE=ghcr.io/getsentry/vroom:25.10.0 +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.10.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e1944842e2..811ebf38e5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 25.10.0 + +### Various fixes & improvements + +- fix: geoip standalone script should check on CONTAINER_ENGINE variable first (#3982) by @aldy505 +- fix: missing `-dir` flag for seaweedfs (#3991) by @aldy505 +- Remove symbolicator volume once (#3994) by @aminvakil +- Remove symbolicator external volume (#3992) by @aminvakil +- chore(spans): Remove old snuba-spans consumer (#3989) by @jjbayer +- Bump redis 6.2.20-alpine (#3988) by @aminvakil +- ref: add `continue-on-error` for codecov action on self-hosted integration tests (#3978) by @aldy505 +- ref: use dedicated `healthcheck` command for symbolicator & remove cron for `symbolicator-cleanup` (#3979) by @aldy505 +- fix(actions): include arch and compose_profiles information on cache keys (#3974) by @aldy505 +- ref: Remove proxy_next_upstream directives (#3973) by @aminvakil +- fix: Unset the proxy when performing the seaweedfs health check (#3959) by @SteppingHat +- fix: logic error in s3 install script (#3965) by @kodebach +- Fix swap allocation in integration test (#3972) by @aminvakil +- chore(tasks) Remove reference to celery (#3962) by @markstory +- Respect uppercase proxy variables (#3949) by @aminvakil +- chore(tasks): Remove the worker and cron containers (#3946) by @markstory +- fix: install behind a proxy (#3944) by @moroine + ## 25.9.0 ### Various fixes & improvements From 6ae40d837a78c2968a28acf952b1beb9911237f8 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 15 Oct 2025 19:18:46 +0000 Subject: [PATCH 266/305] build: Set master version to nightly #skip-changelog --- .env | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env b/.env index 5d2bae9abc6..dfe279267f8 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.10.0 -SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.10.0 -RELAY_IMAGE=ghcr.io/getsentry/relay:25.10.0 -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.10.0 -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.10.0 -VROOM_IMAGE=ghcr.io/getsentry/vroom:25.10.0 -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.10.0 +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 976e06525ba2049fff8bd6c3a0bdc2853e36f2bf Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 8 Nov 2025 09:29:17 +0700 Subject: [PATCH 267/305] fix: remove snuba uptime results consumer (#4027) Saw this error on the self-hosted e2e tests: ``` snuba-uptime-results-consumer-1 | Error: Invalid value for '--storage': 'uptime_monitor_checks' is not one of 'spans', 'metrics_raw', 'errors', 'search_issues', 'generic_metrics_distributions_raw', 'generic_metrics_counters_raw', 'generic_metrics_sets_raw', 'generic_metrics_gauges_raw', 'eap_items', 'groupassignees', 'outcomes_raw', 'querylog', 'functions_raw', 'transactions', 'replays', 'profile_chunks', 'profiles', 'groupedmessages', 'group_attributes'. ``` Seems like we don't need that consumer anymore, since it's moved to EAP. --- docker-compose.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index e7400ae61a3..8e8d50ba145 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -463,13 +463,6 @@ services: command: subscriptions-scheduler-executor --dataset events_analytics_platform --entity eap_items --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-eap-items-subscriptions-consumers --followed-consumer-group=eap_items_group --schedule-ttl=60 --stale-threshold-seconds=900 --health-check-file /tmp/health.txt healthcheck: <<: *file_healthcheck_defaults - snuba-uptime-results-consumer: - <<: *snuba_defaults - command: rust-consumer --storage uptime_monitor_checks --consumer-group snuba-uptime-results --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset --health-check-file /tmp/health.txt - healthcheck: - <<: *file_healthcheck_defaults - profiles: - - feature-complete symbolicator: <<: *restart_policy image: "$SYMBOLICATOR_IMAGE" From 4f6caf7a13ff9326d7bc6778b45ede6ba4e6d2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemens=20B=C3=B6swirth?= <23529132+kodebach@users.noreply.github.com> Date: Mon, 10 Nov 2025 18:37:12 +0100 Subject: [PATCH 268/305] fix(install): add migrate-pgbouncer.sh to install.sh (#4030) --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index c6b3a62a178..b31c9d9ee33 100755 --- a/install.sh +++ b/install.sh @@ -41,6 +41,7 @@ source install/bootstrap-snuba.sh source install/upgrade-postgres.sh source install/ensure-correct-permissions-profiles-dir.sh source install/set-up-and-migrate-database.sh +source install/migrate-pgbouncer.sh source install/geoip.sh source install/setup-js-sdk-assets.sh source install/wrap-up.sh From 2b0757c0d231970aae85c39f9bfaaf0be26026ce Mon Sep 17 00:00:00 2001 From: Stephano Vogel Date: Tue, 11 Nov 2025 01:03:52 +0100 Subject: [PATCH 269/305] Increase default max_suspicious_broken_parts to 100 (#4011) Increase max_suspicious_broken_parts to 100 Increased the max_suspicious_broken_parts setting to adapt to more modern setups --- clickhouse/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clickhouse/config.xml b/clickhouse/config.xml index 28ec384cb62..579095965f8 100644 --- a/clickhouse/config.xml +++ b/clickhouse/config.xml @@ -28,6 +28,6 @@ 1 - 10 + 100 From c7d413c4631e1761c34621f73c5c284b83dc4208 Mon Sep 17 00:00:00 2001 From: "Sascha O. Bacher" <75041473+otoriphoenix@users.noreply.github.com> Date: Tue, 11 Nov 2025 01:04:18 +0100 Subject: [PATCH 270/305] Fix Clickhouse max_server_memory_usage_to_ram_ratio setting (#4025) Co-authored-by: Reinaldy Rafli --- clickhouse/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clickhouse/config.xml b/clickhouse/config.xml index 579095965f8..cc431a8463e 100644 --- a/clickhouse/config.xml +++ b/clickhouse/config.xml @@ -1,6 +1,6 @@ - + warning true From 3af221e4d41d41402563cddda3ad47750e060f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marian=20=C5=A0ime=C4=8Dek?= Date: Wed, 12 Nov 2025 05:19:29 +0100 Subject: [PATCH 271/305] fix: broken link to Errors-Only Mode docs (#4032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marian Šimeček --- .env | 2 +- sentry/sentry.conf.example.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env b/.env index dfe279267f8..7a768f29d5a 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ COMPOSE_PROJECT_NAME=sentry-self-hosted # Set COMPOSE_PROFILES to "feature-complete" to enable all features # To enable errors monitoring only, set COMPOSE_PROFILES=errors-only -# See https://develop.sentry.dev/self-hosted/experimental/errors-only/ +# See https://develop.sentry.dev/self-hosted/optional-features/errors-only/ COMPOSE_PROFILES=feature-complete SENTRY_EVENT_RETENTION_DAYS=90 # You can either use a port number or an IP:PORT combo for SENTRY_BIND diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 38147f7bb02..46a10152171 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -92,7 +92,7 @@ def get_internal_network(): # in your `.env` file. To enable only the error monitoring feature, set # `COMPOSE_PROFILES` to `errors-only`. # -# See https://develop.sentry.dev/self-hosted/experimental/errors-only/ +# See https://develop.sentry.dev/self-hosted/optional-features/errors-only/ SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" # When running in an air-gapped environment, set this to True to entirely disable From 275e7d032c9eeacb02c1c4065dff1dc6bf471081 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 14 Nov 2025 10:10:45 +0700 Subject: [PATCH 272/305] ref: sound SENTRY_DISALLOWED_IPS on the configuration file (#3981) * ref: sound SENTRY_DISALLOWED_IPS on the configuration file To not mislead people and to prevent time spent scrolling on GitHub issues just to fix why requests to private IP addresses are not working. * chore: commented out for visibility purposes --- sentry/sentry.conf.example.py | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 46a10152171..f6f2b6502ca 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -103,6 +103,64 @@ def get_internal_network(): # AI model prices from various public APIs. SENTRY_AIR_GAP = False +# As of 25.9.0 (September 2025 release), Sentry enforces tighter restrictions +# of allowed IP addresses for outgoing requests. This is to prevent +# accidentally leaking sensitive information to third parties. +# +# By default, Sentry will not allow requests to private IP addresses. +# You can override this by configuring the allowed IP addresses here. +# Below is the default value, which is a list of IP addresses that are +# considered "private" and "reserved". +# +# SENTRY_DISALLOWED_IPS: tuple[str, ...] = ( +# # https://en.wikipedia.org/wiki/Reserved_IP_addresses#IPv4 +# "0.0.0.0/8", +# "10.0.0.0/8", +# "100.64.0.0/10", +# "127.0.0.0/8", +# "169.254.0.0/16", +# "172.16.0.0/12", +# "192.0.0.0/29", +# "192.0.2.0/24", +# "192.88.99.0/24", +# "192.168.0.0/16", +# "198.18.0.0/15", +# "198.51.100.0/24", +# "224.0.0.0/4", +# "240.0.0.0/4", +# "255.255.255.255/32", +# # https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses +# # Subnets match the IPv4 subnets above +# "::ffff:0:0/104", +# "::ffff:a00:0/104", +# "::ffff:6440:0/106", +# "::ffff:7f00:0/104", +# "::ffff:a9fe:0/112", +# "::ffff:ac10:0/108", +# "::ffff:c000:0/125", +# "::ffff:c000:200/120", +# "::ffff:c058:6300/120", +# "::ffff:c0a8:0/112", +# "::ffff:c612:0/111", +# "::ffff:c633:6400/120", +# "::ffff:e000:0/100", +# "::ffff:f000:0/100", +# "::ffff:ffff:ffff/128", +# # https://en.wikipedia.org/wiki/Reserved_IP_addresses#IPv6 +# "::1/128", +# "::ffff:0:0/96", +# "64:ff9b::/96", +# "64:ff9b:1::/48", +# "100::/64", +# "2001:0000::/32", +# "2001:20::/28", +# "2001:db8::/32", +# "2002::/16", +# "fc00::/7", +# "fe80::/10", +# "ff00::/8", +# ) + ################ # Node Storage # ################ From fe477b41d937b838146f83a48bbbe705ec959f49 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 14 Nov 2025 10:37:23 +0700 Subject: [PATCH 273/305] feat: statsd configuration through environment variables (#4031) * feat: statsd configuration through environment variables * feat: provide statsd config via environment variables for relay and symbolicator * fix: default statsd value to localhost * Update sentry/sentry.conf.example.py --- .env | 5 +++++ docker-compose.yml | 10 ++++++++-- relay/config.example.yml | 6 +++--- sentry/sentry.conf.example.py | 14 +++++++++----- symbolicator/config.example.yml | 11 ++++------- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/.env b/.env index 7a768f29d5a..d75f1814ef7 100644 --- a/.env +++ b/.env @@ -26,3 +26,8 @@ HEALTHCHECK_FILE_RETRIES=3 HEALTHCHECK_FILE_START_PERIOD=600s # Set SETUP_JS_SDK_ASSETS to 1 to enable the setup of JS SDK assets # SETUP_JS_SDK_ASSETS=1 +# +# Sentry (and its' surrounding services) uses Statsd for metrics collection. +# It's also the proper way to monitor self-hosted Sentry systems. +# Set STATSD_ADDR to a valid IP:PORT combination to enable Statsd metrics collection. +# STATSD_ADDR=127.0.0.1:8125 diff --git a/docker-compose.yml b/docker-compose.yml index 8e8d50ba145..4017e5245d5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -69,6 +69,7 @@ x-sentry-defaults: &sentry_defaults SENTRY_EVENT_RETENTION_DAYS: SENTRY_MAIL_HOST: SENTRY_MAX_EXTERNAL_SOURCEMAP_SIZE: + SENTRY_STATSD_ADDR: "${STATSD_ADDR:-}" volumes: - "sentry-data:/data" - "./sentry:/etc/sentry" @@ -96,8 +97,7 @@ x-snuba-defaults: &snuba_defaults SENTRY_EVENT_RETENTION_DAYS: # If you have statsd server, you can utilize that to monitor self-hosted Snuba containers. # To start, state these environment variables below on your `.env.` file and adjust the options as needed. - SNUBA_STATSD_HOST: # Example value: "100.100.123.123". Must be an IP address, not domain name - SNUBA_STATSD_PORT: # Example value: 8125 + SNUBA_STATSD_ADDR: "${STATSD_ADDR:-}" services: smtp: <<: *restart_policy @@ -466,6 +466,8 @@ services: symbolicator: <<: *restart_policy image: "$SYMBOLICATOR_IMAGE" + environment: + SYMBOLICATOR_STATSD_ADDR: ${STATSD_ADDR:-127.0.0.1:8125} command: run -c /etc/symbolicator/config.yml volumes: - "sentry-symbolicator:/data" @@ -700,6 +702,8 @@ services: relay: <<: *restart_policy image: "$RELAY_IMAGE" + environment: + RELAY_STATSD_ADDR: ${STATSD_ADDR:-127.0.0.1:8125} volumes: - type: bind read_only: true @@ -726,6 +730,7 @@ services: TASKBROKER_KAFKA_CLUSTER: "kafka:9092" TASKBROKER_KAFKA_DEADLETTER_CLUSTER: "kafka:9092" TASKBROKER_DB_PATH: "/opt/sqlite/taskbroker-activations.sqlite" + TASKBROKER_STATSD_ADDR: ${STATSD_ADDR:-127.0.0.1:8125} volumes: - sentry-taskbroker:/opt/sqlite depends_on: @@ -794,6 +799,7 @@ services: # Separated by commas. Leaving this unset will default to the systems dns # resolver. #UPTIME_CHECKER_HTTP_CHECKER_DNS_NAMESERVERS: "8.8.8.8,8.8.4.4" + UPTIME_CHECKER_STATSD_ADDR: ${STATSD_ADDR:-127.0.0.1:8125} depends_on: kafka: <<: *depends_on-healthy diff --git a/relay/config.example.yml b/relay/config.example.yml index 06c73079564..007f81309f5 100644 --- a/relay/config.example.yml +++ b/relay/config.example.yml @@ -27,9 +27,9 @@ processing: # If you have statsd server, you can utilize that to monitor self-hosted Relay. # To start, uncomment the following `metrics` section and adjust the options as needed. # -# metrics: -# statsd: "100.100.123.123:8125" # It is recommended to use IP address instead of domain name -# prefix: "sentry.relay" # Adjust this to your needs, default is "sentry.relay" +metrics: + statsd: "${RELAY_STATSD_ADDR}" + prefix: "sentry.relay" # Adjust this to your needs, default is "sentry.relay" # sample_rate: 1.0 # Adjust this to your needs, default is 1.0 # # `periodic_secs` is the interval for periodic metrics emitted from Relay. # # Setting it to `0` seconds disables the periodic metrics. diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index f6f2b6502ca..26a3910d9c3 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -521,10 +521,14 @@ def get_internal_network(): # # To start, uncomment the following line and adjust the options as needed. -# SENTRY_METRICS_BACKEND = 'sentry.metrics.statsd.StatsdMetricsBackend' -# SENTRY_METRICS_OPTIONS: dict[str, Any] = { -# 'host': '100.100.123.123', # It is recommended to use IP address instead of domain name -# 'port': 8125, -# } +SENTRY_STATSD_ADDR = env("SENTRY_STATSD_ADDR") +if SENTRY_STATSD_ADDR: + host, _, port = SENTRY_STATSD_ADDR.partition(":") + port = int(port or 8125) + SENTRY_METRICS_BACKEND = 'sentry.metrics.statsd.StatsdMetricsBackend' + SENTRY_METRICS_OPTIONS: dict[str, Any] = { + 'host': host, + 'port': port, + } # SENTRY_METRICS_SAMPLE_RATE = 1.0 # Adjust this to your needs, default is 1.0 # SENTRY_METRICS_PREFIX = "sentry." # Adjust this to your needs, default is "sentry." diff --git a/symbolicator/config.example.yml b/symbolicator/config.example.yml index de716de8c4c..f0da86d4c25 100644 --- a/symbolicator/config.example.yml +++ b/symbolicator/config.example.yml @@ -3,13 +3,10 @@ cache_dir: "/data" bind: "0.0.0.0:3021" logging: level: "warn" -metrics: - statsd: null + sentry_dsn: null # TODO: Automatically fill this with the internal project DSN # If you have statsd server, you can utilize that to monitor self-hosted Symbolicator. -# To start, uncomment the following line and adjust the options as needed. -# -# metrics: -# statsd: "100.100.123.123:8125" # It is recommended to use IP address instead of domain name -# prefix: "sentry.symbolicator" # Adjust this to your needs, default is "symbolicator" +metrics: + statsd: "${SYMBOLICATOR_STATSD_ADDR}" # It is recommended to use IP address instead of domain name + prefix: "sentry.symbolicator" # Adjust this to your needs, default is "symbolicator" From 9ce49daa1c635411195824c790eac305c900341a Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Sat, 15 Nov 2025 18:06:53 +0000 Subject: [PATCH 274/305] release: 25.11.0 --- .env | 14 +++++++------- CHANGELOG.md | 12 ++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.env b/.env index d75f1814ef7..fbc8c530ff5 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly -SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly -RELAY_IMAGE=ghcr.io/getsentry/relay:nightly -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly -VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.11.0 +SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.11.0 +RELAY_IMAGE=ghcr.io/getsentry/relay:25.11.0 +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.11.0 +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.11.0 +VROOM_IMAGE=ghcr.io/getsentry/vroom:25.11.0 +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.11.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 811ebf38e5b..57278ed4dd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 25.11.0 + +### Various fixes & improvements + +- feat: statsd configuration through environment variables (#4031) by @aldy505 +- ref: sound SENTRY_DISALLOWED_IPS on the configuration file (#3981) by @aldy505 +- fix: broken link to Errors-Only Mode docs (#4032) by @mariansimecek +- Fix Clickhouse max_server_memory_usage_to_ram_ratio setting (#4025) by @otoriphoenix +- Increase default max_suspicious_broken_parts to 100 (#4011) by @stevenobird +- fix(install): add migrate-pgbouncer.sh to install.sh (#4030) by @kodebach +- fix: remove snuba uptime results consumer (#4027) by @aldy505 + ## 25.10.0 ### Various fixes & improvements From 522bb032455dcc4f1cbf13ac3e93ed8a8821de98 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 17 Nov 2025 05:18:01 +0700 Subject: [PATCH 275/305] fix: missing SYMBOLICATOR_STATSD_ADDR environment var for symbolicator-cleanup (#4042) --- docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 4017e5245d5..bcc858c0b96 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -481,6 +481,8 @@ services: symbolicator-cleanup: <<: *restart_policy image: "$SYMBOLICATOR_IMAGE" + environment: + SYMBOLICATOR_STATSD_ADDR: ${STATSD_ADDR:-127.0.0.1:8125} command: "cleanup -c /etc/symbolicator/config.yml --repeat 1h" volumes: - "sentry-symbolicator:/data" From 370ee99cbd53646e918dc23369118926a087b02a Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 19 Nov 2025 08:32:38 +0700 Subject: [PATCH 276/305] chore: uptime checker is missing on the release issue (#4047) --- .github/ISSUE_TEMPLATE/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/release.yml b/.github/ISSUE_TEMPLATE/release.yml index 545e733befe..36f872763a5 100644 --- a/.github/ISSUE_TEMPLATE/release.yml +++ b/.github/ISSUE_TEMPLATE/release.yml @@ -15,6 +15,7 @@ body: - [ ] [`snuba`](https://github.com/getsentry/snuba/actions/workflows/release.yml) - [ ] [`symbolicator`](https://github.com/getsentry/symbolicator/actions/workflows/release.yml) - [ ] [`vroom`](https://github.com/getsentry/vroom/actions/workflows/release.yaml) + - [ ] [`uptime-checker`](https://github.com/getsentry/uptime-checker/actions/workflows/release.yml) - [ ] [`taskbroker`](https://github.com/getsentry/taskbroker/actions/workflows/release.yml) - [ ] Release self-hosted. - [ ] [Prepare the `self-hosted` release](https://github.com/getsentry/self-hosted/actions/workflows/release.yml) (_replace with publish issue repo link_). From 1e781153b8857d331a68910a3675530197784270 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Wed, 19 Nov 2025 02:02:09 +0000 Subject: [PATCH 277/305] build: Set master version to nightly #skip-changelog --- .env | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env b/.env index fbc8c530ff5..d75f1814ef7 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.11.0 -SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.11.0 -RELAY_IMAGE=ghcr.io/getsentry/relay:25.11.0 -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.11.0 -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.11.0 -VROOM_IMAGE=ghcr.io/getsentry/vroom:25.11.0 -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.11.0 +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From f6014fd2dc86e3e2116ca410646cc74864feff1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:42:40 +0700 Subject: [PATCH 278/305] build(deps): bump actions/checkout from 5 to 6 (#4059) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/fast-revert.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/shellcheck.yml | 2 +- .github/workflows/test.yml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/fast-revert.yml b/.github/workflows/fast-revert.yml index 6b88ed831a5..7a52386f0ab 100644 --- a/.github/workflows/fast-revert.yml +++ b/.github/workflows/fast-revert.yml @@ -19,7 +19,7 @@ jobs: if: | github.event_name == 'workflow_dispatch' || github.event.label.name == 'Trigger: Revert' steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: token: ${{ secrets.BUMP_SENTRY_TOKEN }} - uses: getsentry/action-fast-revert@v2.0.1 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 35e1183b6e3..53dfb67c6e4 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -12,7 +12,7 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: 3.x diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d4bacd7aed1..a0bc7a8ce68 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,7 +27,7 @@ jobs: with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: token: ${{ steps.token.outputs.token }} fetch-depth: 0 @@ -48,7 +48,7 @@ jobs: name: Create release on self-hosted dogfood instance needs: release steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: getsentry/action-release@v3 diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 692da9f4a8f..8e991d8b9f2 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Repository checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 49298277c4f..fed6749de15 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: name: ${{ matrix.os == 'ubuntu-24.04-arm' && 'unit tests (arm64)' || 'unit tests' }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Get Compose uses: ./get-compose-action @@ -56,7 +56,7 @@ jobs: CONTAINER_ENGINE_PODMAN: ${{ matrix.container_engine == 'podman' && '1' || '0' }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Podman if: matrix.container_engine == 'podman' From 61c50780b609ebaa0583fe32e684b7938c588a79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:43:32 +0700 Subject: [PATCH 279/305] build(deps): bump actions/create-github-app-token from 2.1.4 to 2.2.0 (#4058) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.1.4 to 2.2.0. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/67018539274d69449ef7c02e8e71183d1719ab42...7e473efe3cb98aa54f8d4bac15400b15fad77d94) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a0bc7a8ce68..a6c10d29fe3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4 + uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From 5a670d1c5fd232c95b19ce42575ba011b82d6716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemens=20B=C3=B6swirth?= <23529132+kodebach@users.noreply.github.com> Date: Fri, 28 Nov 2025 01:23:21 +0100 Subject: [PATCH 280/305] fix: ensure seaweedfs lifecycle policy is set correctly (#4040) --- install/bootstrap-s3-nodestore.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh index c2cf91669f5..98d934b4461 100644 --- a/install/bootstrap-s3-nodestore.sh +++ b/install/bootstrap-s3-nodestore.sh @@ -62,7 +62,11 @@ if [[ $(echo "$bucket_list" | tail -1 | awk '{print $3}') != 's3://nodestore' ]] $dc exec seaweedfs mkdir -p /data/idx/ $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' mb s3://nodestore +else + echo "Node store already exists, skipping creation..." +fi +if [[ -z "${APPLY_AUTOMATIC_CONFIG_UPDATES:-}" || "$APPLY_AUTOMATIC_CONFIG_UPDATES" == 1 ]]; then # XXX(aldy505): Should we refactor this? lifecycle_policy=$( cat < EOF ) - $dc exec seaweedfs sh -c "printf '%s' '$lifecycle_policy' > /tmp/nodestore-lifecycle-policy.xml" - $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' setlifecycle /tmp/nodestore-lifecycle-policy.xml s3://nodestore echo "Making sure the bucket lifecycle policy is all set up correctly..." + $dc exec seaweedfs sh -c "printf '%s' '$lifecycle_policy' > /tmp/nodestore-lifecycle-policy.xml" + $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' setlifecycle /tmp/nodestore-lifecycle-policy.xml s3://nodestore $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' getlifecycle s3://nodestore -else - echo "Node store already exists, skipping..." fi echo "${_endgroup}" From 84ebc583de7ef57c32fc82f5660fa5f3d1356242 Mon Sep 17 00:00:00 2001 From: Tony Xiao Date: Fri, 28 Nov 2025 02:30:28 -0500 Subject: [PATCH 281/305] fix(profiling): Ingest profile file path (#4060) * fix(profiling): Ingest profile file path `ingest-profiles` is now using vroomrs to ingest profiles instead of writing through vroom. For self-hosted, we need to make sure filestore for profiles is properly configured so vroom can find the ingested profiles. * feat: move profiling data to seaweedfs * feat: review from Sentry * Apply suggestions from code review Co-authored-by: Burak Yigit Kaya * ref: volume migration tests * ref: execute file creation from vroom container * fix: brainfart * debug * hack * more debug * now I know what I'm missing out * explicitly state feature complete * try to pull vroom image * should only run when COMPOSE_PROFILES is feature complete * using run invoked weed instead of empty shell * execute the upload script from vroom container * execute apt command as root * gonna sleep * missing endgroup * missing sh * directly execute s3cmd and do 'wc' outside out the container * why did other test start failing * manual cleanup * vroom is not a persistent volume * what about not removing the seaweed volume --------- Co-authored-by: Reinaldy Rafli Co-authored-by: Burak Yigit Kaya --- ...test.sh => bootstrap-s3-nodestore-test.sh} | 0 _unit-test/bootstrap-s3-profiles-test.sh | 37 ++++++ docker-compose.yml | 4 +- install.sh | 1 + install/bootstrap-s3-nodestore.sh | 2 +- install/bootstrap-s3-profiles.sh | 118 ++++++++++++++++++ sentry/config.example.yml | 12 ++ 7 files changed, 172 insertions(+), 2 deletions(-) rename _unit-test/{bootstrap-s3-seaweed-test.sh => bootstrap-s3-nodestore-test.sh} (100%) create mode 100755 _unit-test/bootstrap-s3-profiles-test.sh create mode 100644 install/bootstrap-s3-profiles.sh diff --git a/_unit-test/bootstrap-s3-seaweed-test.sh b/_unit-test/bootstrap-s3-nodestore-test.sh similarity index 100% rename from _unit-test/bootstrap-s3-seaweed-test.sh rename to _unit-test/bootstrap-s3-nodestore-test.sh diff --git a/_unit-test/bootstrap-s3-profiles-test.sh b/_unit-test/bootstrap-s3-profiles-test.sh new file mode 100755 index 00000000000..660247fdbaf --- /dev/null +++ b/_unit-test/bootstrap-s3-profiles-test.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +source _unit-test/_test_setup.sh +source install/dc-detect-version.sh +source install/create-docker-volumes.sh +source install/ensure-files-from-examples.sh +export COMPOSE_PROFILES="feature-complete" +$dc pull vroom +source install/ensure-correct-permissions-profiles-dir.sh + +# Generate some random files on `sentry-vroom` volume for testing +$dc run --rm --no-deps -v sentry-vroom:/var/vroom/sentry-profiles --entrypoint /bin/bash vroom -c ' + for i in $(seq 1 1000); do + echo This is test file $i > /var/vroom/sentry-profiles/test_file_$i.txt + done +' + +# Set the flag to apply automatic updates +export APPLY_AUTOMATIC_CONFIG_UPDATES=1 + +# Here we're just gonna test to run it multiple times +# Only to make sure it doesn't break +for i in $(seq 1 5); do + source install/bootstrap-s3-profiles.sh +done + +# Ensure that the files have been migrated to SeaweedFS +migrated_files_count=$($dc exec seaweedfs s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=seaweedfs:8333 --host-bucket="seaweedfs:8333/%(bucket)" ls s3://profiles/ | wc -l) +if [[ "$migrated_files_count" -ne 1000 ]]; then + echo "Error: Expected 1000 migrated files, but found $migrated_files_count" + exit 1 +fi + +# Manual cleanup, otherwise `create-docker-volumes.sh` will fail +$dc down -v --remove-orphans + +report_success diff --git a/docker-compose.yml b/docker-compose.yml index bcc858c0b96..10cb21716b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -752,7 +752,9 @@ services: environment: SENTRY_KAFKA_BROKERS_PROFILING: "kafka:9092" SENTRY_KAFKA_BROKERS_OCCURRENCES: "kafka:9092" - SENTRY_BUCKET_PROFILES: file:///var/vroom/sentry-profiles + SENTRY_BUCKET_PROFILES: "s3://profiles?region=us-east-1&endpoint=seaweedfs:8333&s3ForcePathStyle=true&disableSSL=true" + AWS_ACCESS_KEY: "sentry" + AWS_SECRET_KEY: "sentry" SENTRY_SNUBA_HOST: "http://snuba-api:1218" volumes: - sentry-vroom:/var/vroom/sentry-profiles diff --git a/install.sh b/install.sh index b31c9d9ee33..648f8184543 100755 --- a/install.sh +++ b/install.sh @@ -40,6 +40,7 @@ source install/bootstrap-s3-nodestore.sh source install/bootstrap-snuba.sh source install/upgrade-postgres.sh source install/ensure-correct-permissions-profiles-dir.sh +source install/bootstrap-s3-profiles.sh source install/set-up-and-migrate-database.sh source install/migrate-pgbouncer.sh source install/geoip.sh diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh index 98d934b4461..8170131a873 100644 --- a/install/bootstrap-s3-nodestore.sh +++ b/install/bootstrap-s3-nodestore.sh @@ -1,6 +1,6 @@ echo "${_group}Bootstrapping seaweedfs (node store)..." -$dc up --wait seaweedfs postgres +start_service_and_wait_ready seaweedfs postgres $dc exec -e "HTTP_PROXY=${HTTP_PROXY:-}" -e "HTTPS_PROXY=${HTTPS_PROXY:-}" -e "NO_PROXY=${NO_PROXY:-}" -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" seaweedfs apk add --no-cache s3cmd $dc exec seaweedfs mkdir -p /data/idx/ s3cmd="$dc exec seaweedfs s3cmd" diff --git a/install/bootstrap-s3-profiles.sh b/install/bootstrap-s3-profiles.sh new file mode 100644 index 00000000000..326dce583dc --- /dev/null +++ b/install/bootstrap-s3-profiles.sh @@ -0,0 +1,118 @@ +# The purpose of this file is to have both `sentry`-based containers and `vroom` use the same bucket for profiling. +# On pre-25.10.0, we have a `sentry-vroom` volume which stores the profiling data however, since this version, +# the behavior changed, and `vroomrs` now ingests profiles directly. Both services must share the same bucket, +# but at the time of this writing, it's not possible because the `sentry-vroom` volume has ownership set to `vroom:vroom`. +# This prevents the `sentry`-based containers from performing read/write operations on that volume. +# +# Therefore, this script should do the following: +# 1. Check if there are any files inside the `sentry-vroom` volume. +# 2. If (1) finds files, copy those files into a "profiles" bucket on SeaweedFS. +# 3. Point `filestore-profiles` and vroom to the SeaweedFS "profiles" bucket. + +# Should only run when `$COMPOSE_PROFILES` is set to `feature-complete` +if [[ "$COMPOSE_PROFILES" == "feature-complete" ]]; then + echo "${_group}Bootstrapping seaweedfs (profiles)..." + + start_service_and_wait_ready seaweedfs + $dc exec -e "HTTP_PROXY=${HTTP_PROXY:-}" -e "HTTPS_PROXY=${HTTPS_PROXY:-}" -e "NO_PROXY=${NO_PROXY:-}" -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" seaweedfs apk add --no-cache s3cmd + s3cmd="$dc exec seaweedfs s3cmd" + + bucket_list=$($s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' ls) + + if [[ $(echo "$bucket_list" | tail -1 | awk '{print $3}') != 's3://profiles' ]]; then + apply_config_changes_profiles=0 + # Only touch if no existing profiles config is found + if ! grep -q "filestore.profiles-backend" $SENTRY_CONFIG_YML; then + if [[ -z "${APPLY_AUTOMATIC_CONFIG_UPDATES:-}" ]]; then + echo + echo "We are migrating the Profiles data directory from the 'sentry-vroom' volume to SeaweedFS." + echo "This migration will ensure profiles ingestion works correctly with the new 'vroomrs'" + echo "and allows both 'sentry' and 'vroom' to transition smoothly." + echo "To complete this, your sentry/config.yml file needs to be modified." + echo "Would you like us to perform this modification automatically?" + echo + + yn="" + until [ ! -z "$yn" ]; do + read -p "y or n? " yn + case $yn in + y | yes | 1) + export apply_config_changes_profiles=1 + echo + echo -n "Thank you." + ;; + n | no | 0) + export apply_config_changes_profiles=0 + echo + echo -n "Alright, you will need to update your sentry/config.yml file manually before running 'docker compose up'." + ;; + *) yn="" ;; + esac + done + + echo + echo "To avoid this prompt in the future, use one of these flags:" + echo + echo " --apply-automatic-config-updates" + echo " --no-apply-automatic-config-updates" + echo + echo "or set the APPLY_AUTOMATIC_CONFIG_UPDATES environment variable:" + echo + echo " APPLY_AUTOMATIC_CONFIG_UPDATES=1 to apply automatic updates" + echo " APPLY_AUTOMATIC_CONFIG_UPDATES=0 to not apply automatic updates" + echo + sleep 5 + fi + + if [[ "$APPLY_AUTOMATIC_CONFIG_UPDATES" == 1 || "$apply_config_changes_profiles" == 1 ]]; then + profiles_config=$(sed -n '/filestore.profiles-backend/,/s3v4"/{p}' sentry/config.example.yml) + echo "$profiles_config" >>$SENTRY_CONFIG_YML + fi + fi + + $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' mb s3://profiles + + # Check if there are files in the sentry-vroom volume + start_service_and_wait_ready vroom + vroom_files_count=$($dc exec vroom sh -c "find /var/vroom/sentry-profiles -type f | wc -l") + if [[ "$vroom_files_count" -gt 0 ]]; then + echo "Migrating $vroom_files_count files from 'sentry-vroom' volume to 'profiles' bucket on SeaweedFS..." + + # Use a temporary container to copy files from the volume to SeaweedFS + + $dc exec -e "HTTP_PROXY=${HTTP_PROXY:-}" -e "HTTPS_PROXY=${HTTPS_PROXY:-}" -e "NO_PROXY=${NO_PROXY:-}" -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" -u root vroom sh -c 'mkdir -p /var/lib/apt/lists/partial && apt-get update && apt-get install -y --no-install-recommends s3cmd' + $dc exec vroom sh -c 's3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=seaweedfs:8333 --host-bucket="seaweedfs:8333/%(bucket)" sync /var/vroom/sentry-profiles/ s3://profiles/' + + echo "Migration completed." + else + echo "No files found in 'sentry-vroom' volume. Skipping files migration." + fi + else + echo "'profiles' bucket already exists on SeaweedFS. Skipping creation." + fi + + if [[ -z "${APPLY_AUTOMATIC_CONFIG_UPDATES:-}" || "$APPLY_AUTOMATIC_CONFIG_UPDATES" == 1 ]]; then + lifecycle_policy=$( + cat < + + + Sentry-Profiles-Rule + Enabled + + + $SENTRY_EVENT_RETENTION_DAYS + + + +EOF + ) + + $dc exec seaweedfs sh -c "printf '%s' '$lifecycle_policy' > /tmp/profiles-lifecycle-policy.xml" + $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' setlifecycle /tmp/profiles-lifecycle-policy.xml s3://profiles + + echo "Making sure the bucket lifecycle policy is all set up correctly..." + $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' getlifecycle s3://profiles + fi + echo "${_endgroup}" +fi diff --git a/sentry/config.example.yml b/sentry/config.example.yml index fefe9511b81..f1c3669d4f0 100644 --- a/sentry/config.example.yml +++ b/sentry/config.example.yml @@ -96,6 +96,18 @@ releasefile.cache-path: '/data/releasefile-cache' # secret_key: 'XXXXXXX' # bucket_name: 's3-bucket-name' +filestore.profiles-backend: 's3' +filestore.profiles-options: + bucket_acl: "private" + default_acl: "private" + access_key: "sentry" + secret_key: "sentry" + bucket_name: "profiles" + region_name: "us-east-1" + endpoint_url: "http://seaweedfs:8333" + addressing_style: "path" + signature_version: "s3v4" + symbolicator.enabled: true symbolicator.options: url: "http://symbolicator:3021" From a73563f172bba99d24dea1de3a06aeb353b3e3bb Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 28 Nov 2025 16:27:39 +0700 Subject: [PATCH 282/305] chore: remove some more unused directories (#4046) * chore: remove some more unused directories * chore: remove debugging logs --- action.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/action.yaml b/action.yaml index 7f7a98f84fc..89f1dd92692 100644 --- a/action.yaml +++ b/action.yaml @@ -47,6 +47,9 @@ runs: run: | ### Inspired by https://github.com/endersonmenezes/free-disk-space ### sudo rm -rf /usr/local/.ghcup + sudo rm -rf /home/runner/Android /usr/local/lib/android /opt/android /usr/local/android-sdk + sudo rm -rf /usr/share/dotnet /usr/share/doc/dotnet-* + df -h - name: Setup dev environment shell: bash From c9aa6268f54db434c200d2ce79912aba9413dd18 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 28 Nov 2025 09:48:01 +0000 Subject: [PATCH 283/305] Add `dcx` shortcut for docker compose exec with HTTP proxy env vars (#4067) * Initial plan * Add dcep shortcut for docker compose exec with http proxy Co-authored-by: BYK <126780+BYK@users.noreply.github.com> * Quote environment variable values in dcep shortcut Co-authored-by: BYK <126780+BYK@users.noreply.github.com> * Rename dcep to dcx (docker compose exec shortcut) Co-authored-by: BYK <126780+BYK@users.noreply.github.com> * Move dcx after if/else block and use exec_proxy_args for DRY Co-authored-by: BYK <126780+BYK@users.noreply.github.com> * Remove exec_proxy_args and inline proxy flags in dcx Co-authored-by: BYK <126780+BYK@users.noreply.github.com> * Add exec_proxy_args variable and use it in dcx definition Co-authored-by: BYK <126780+BYK@users.noreply.github.com> * Use $dcx shortcut in bootstrap-s3-profiles.sh Co-authored-by: aldy505 <7274326+aldy505@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: BYK <126780+BYK@users.noreply.github.com> Co-authored-by: Reinaldy Rafli Co-authored-by: aldy505 <7274326+aldy505@users.noreply.github.com> --- install/bootstrap-s3-nodestore.sh | 2 +- install/bootstrap-s3-profiles.sh | 4 ++-- install/dc-detect-version.sh | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh index 8170131a873..407e0ccd333 100644 --- a/install/bootstrap-s3-nodestore.sh +++ b/install/bootstrap-s3-nodestore.sh @@ -1,7 +1,7 @@ echo "${_group}Bootstrapping seaweedfs (node store)..." start_service_and_wait_ready seaweedfs postgres -$dc exec -e "HTTP_PROXY=${HTTP_PROXY:-}" -e "HTTPS_PROXY=${HTTPS_PROXY:-}" -e "NO_PROXY=${NO_PROXY:-}" -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" seaweedfs apk add --no-cache s3cmd +$dcx seaweedfs apk add --no-cache s3cmd $dc exec seaweedfs mkdir -p /data/idx/ s3cmd="$dc exec seaweedfs s3cmd" diff --git a/install/bootstrap-s3-profiles.sh b/install/bootstrap-s3-profiles.sh index 326dce583dc..749d4c37223 100644 --- a/install/bootstrap-s3-profiles.sh +++ b/install/bootstrap-s3-profiles.sh @@ -14,7 +14,7 @@ if [[ "$COMPOSE_PROFILES" == "feature-complete" ]]; then echo "${_group}Bootstrapping seaweedfs (profiles)..." start_service_and_wait_ready seaweedfs - $dc exec -e "HTTP_PROXY=${HTTP_PROXY:-}" -e "HTTPS_PROXY=${HTTPS_PROXY:-}" -e "NO_PROXY=${NO_PROXY:-}" -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" seaweedfs apk add --no-cache s3cmd + $dcx seaweedfs apk add --no-cache s3cmd s3cmd="$dc exec seaweedfs s3cmd" bucket_list=$($s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' ls) @@ -80,7 +80,7 @@ if [[ "$COMPOSE_PROFILES" == "feature-complete" ]]; then # Use a temporary container to copy files from the volume to SeaweedFS - $dc exec -e "HTTP_PROXY=${HTTP_PROXY:-}" -e "HTTPS_PROXY=${HTTPS_PROXY:-}" -e "NO_PROXY=${NO_PROXY:-}" -e "http_proxy=${http_proxy:-}" -e "https_proxy=${https_proxy:-}" -e "no_proxy=${no_proxy:-}" -u root vroom sh -c 'mkdir -p /var/lib/apt/lists/partial && apt-get update && apt-get install -y --no-install-recommends s3cmd' + $dcx -u root vroom sh -c 'mkdir -p /var/lib/apt/lists/partial && apt-get update && apt-get install -y --no-install-recommends s3cmd' $dc exec vroom sh -c 's3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=seaweedfs:8333 --host-bucket="seaweedfs:8333/%(bucket)" sync /var/vroom/sentry-profiles/ s3://profiles/' echo "Migration completed." diff --git a/install/dc-detect-version.sh b/install/dc-detect-version.sh index f7a4cbdda97..909414b463c 100644 --- a/install/dc-detect-version.sh +++ b/install/dc-detect-version.sh @@ -48,6 +48,7 @@ else fi proxy_args="--build-arg HTTP_PROXY=${HTTP_PROXY:-} --build-arg HTTPS_PROXY=${HTTPS_PROXY:-} --build-arg NO_PROXY=${NO_PROXY:-} --build-arg http_proxy=${http_proxy:-} --build-arg https_proxy=${https_proxy:-} --build-arg no_proxy=${no_proxy:-}" +exec_proxy_args="-e HTTP_PROXY=${HTTP_PROXY:-} -e HTTPS_PROXY=${HTTPS_PROXY:-} -e NO_PROXY=${NO_PROXY:-} -e http_proxy=${http_proxy:-} -e https_proxy=${https_proxy:-} -e no_proxy=${no_proxy:-}" if [[ "$CONTAINER_ENGINE" == "podman" ]]; then proxy_args_dc="--podman-build-args HTTP_PROXY=${HTTP_PROXY:-},HTTPS_PROXY=${HTTPS_PROXY:-},NO_PROXY=${NO_PROXY:-},http_proxy=${http_proxy:-},https_proxy=${https_proxy:-},no_proxy=${no_proxy:-}" # Disable pod creation as these are one-off commands and creating a pod @@ -60,6 +61,7 @@ else fi dcb="$dc build $proxy_args" dbuild="$CONTAINER_ENGINE build $proxy_args" +dcx="$dc exec $exec_proxy_args" echo "$dcr" # Utility function to handle --wait with docker and podman function start_service_and_wait_ready() { From b4695677db6b45f0b40c0668a174b2034276b26d Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 1 Dec 2025 18:40:07 +0000 Subject: [PATCH 284/305] release: 25.11.1 --- .env | 14 +++++++------- CHANGELOG.md | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.env b/.env index d75f1814ef7..ce4a2769740 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly -SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly -RELAY_IMAGE=ghcr.io/getsentry/relay:nightly -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly -VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.11.1 +SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.11.1 +RELAY_IMAGE=ghcr.io/getsentry/relay:25.11.1 +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.11.1 +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.11.1 +VROOM_IMAGE=ghcr.io/getsentry/vroom:25.11.1 +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.11.1 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 57278ed4dd2..d6fad2e5eee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 25.11.1 + +### Build / dependencies / internal 🔧 + +- chore: remove some more unused directories by @aldy505 in [#4046](https://github.com/getsentry/self-hosted/pull/4046) +- build(deps): bump actions/create-github-app-token from 2.1.4 to 2.2.0 by @dependabot in [#4058](https://github.com/getsentry/self-hosted/pull/4058) +- build(deps): bump actions/checkout from 5 to 6 by @dependabot in [#4059](https://github.com/getsentry/self-hosted/pull/4059) +- chore: uptime checker is missing on the release issue by @aldy505 in [#4047](https://github.com/getsentry/self-hosted/pull/4047) + +### Bug Fixes 🐛 + +- fix(profiling): Ingest profile file path by @Zylphrex in [#4060](https://github.com/getsentry/self-hosted/pull/4060) +- fix: ensure seaweedfs lifecycle policy is set correctly by @kodebach in [#4040](https://github.com/getsentry/self-hosted/pull/4040) +- fix: missing SYMBOLICATOR_STATSD_ADDR environment var for symbolicator-cleanup by @aldy505 in [#4042](https://github.com/getsentry/self-hosted/pull/4042) + +### Other + +- Add `dcx` shortcut for docker compose exec with HTTP proxy env vars by @copilot-swe-agent in [#4067](https://github.com/getsentry/self-hosted/pull/4067) + ## 25.11.0 ### Various fixes & improvements From 73e8b0b0735f9dbf50bf0d63edc3802152322e0c Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Mon, 1 Dec 2025 11:59:47 -0800 Subject: [PATCH 285/305] feat(release): Manually run post release script (#4073) manually run post release script --- .env | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env b/.env index ce4a2769740..d75f1814ef7 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.11.1 -SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.11.1 -RELAY_IMAGE=ghcr.io/getsentry/relay:25.11.1 -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.11.1 -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.11.1 -VROOM_IMAGE=ghcr.io/getsentry/vroom:25.11.1 -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.11.1 +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From d53bad58ca615619d444f0e6e675bf12fe031c85 Mon Sep 17 00:00:00 2001 From: Max Wittig Date: Tue, 2 Dec 2025 01:23:02 +0100 Subject: [PATCH 286/305] Add shm_size configuration back to postgres (#4072) --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 10cb21716b7..846bf12556a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -146,6 +146,7 @@ services: POSTGRES_HOST_AUTH_METHOD: "trust" volumes: - "sentry-postgres:/var/lib/postgresql/data" + shm_size: 256m pgbouncer: <<: *restart_policy image: "edoburu/pgbouncer:v1.24.1-p1" From ebace8c6628c0ecedbccdf996aad65982bcfe7d8 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Wed, 3 Dec 2025 18:57:54 +0700 Subject: [PATCH 287/305] fix: grep seaweedfs bucket name instead of using awk (#4076) * fix: grep seaweedfs bucket name instead of using awk Closes https://github.com/getsentry/self-hosted/issues/4075 * fix: inverted logic gate * chore: file permission --- _unit-test/multiple-seaweedfs-bucket-test.sh | 39 ++++++++++++++++++++ install/bootstrap-s3-nodestore.sh | 2 +- install/bootstrap-s3-profiles.sh | 2 +- 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100755 _unit-test/multiple-seaweedfs-bucket-test.sh diff --git a/_unit-test/multiple-seaweedfs-bucket-test.sh b/_unit-test/multiple-seaweedfs-bucket-test.sh new file mode 100755 index 00000000000..6bfa5957842 --- /dev/null +++ b/_unit-test/multiple-seaweedfs-bucket-test.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +source _unit-test/_test_setup.sh +source install/dc-detect-version.sh +source install/create-docker-volumes.sh + +start_service_and_wait_ready seaweedfs + +$dcx seaweedfs apk add --no-cache s3cmd +s3cmd="$dc exec seaweedfs s3cmd" + +# Create multiple buckets for testing +buckets=(bucket1 bucket2 bucket3) +for bucket in "${buckets[@]}"; do + $s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' mb s3://$bucket +done + +# Verify that all buckets were created successfully +bucket_list=$($s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' ls) +for bucket in "${buckets[@]}"; do + if ! echo "$bucket_list" | grep -q "s3://$bucket"; then + echo "Error: Bucket s3://$bucket was not created successfully." + exit 1 + fi +done + +# Can find "bucket2" +if ! echo "$bucket_list" | grep -q "s3://bucket2"; then + echo "Error: Bucket s3://bucket2 was not found." + exit 1 +fi + +# Can't find "bucket5", should not exist +if echo "$bucket_list" | grep -q "s3://bucket5"; then + echo "Error: Bucket s3://bucket5 should not exist." + exit 1 +fi + +report_success diff --git a/install/bootstrap-s3-nodestore.sh b/install/bootstrap-s3-nodestore.sh index 407e0ccd333..02a243d1c1d 100644 --- a/install/bootstrap-s3-nodestore.sh +++ b/install/bootstrap-s3-nodestore.sh @@ -7,7 +7,7 @@ s3cmd="$dc exec seaweedfs s3cmd" bucket_list=$($s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' ls) -if [[ $(echo "$bucket_list" | tail -1 | awk '{print $3}') != 's3://nodestore' ]]; then +if ! echo "$bucket_list" | grep -q "s3://nodestore"; then apply_config_changes_nodestore=0 # Only touch if no existing nodestore config is found if ! grep -q "SENTRY_NODESTORE" $SENTRY_CONFIG_PY; then diff --git a/install/bootstrap-s3-profiles.sh b/install/bootstrap-s3-profiles.sh index 749d4c37223..447570a9d22 100644 --- a/install/bootstrap-s3-profiles.sh +++ b/install/bootstrap-s3-profiles.sh @@ -19,7 +19,7 @@ if [[ "$COMPOSE_PROFILES" == "feature-complete" ]]; then bucket_list=$($s3cmd --access_key=sentry --secret_key=sentry --no-ssl --region=us-east-1 --host=localhost:8333 --host-bucket='localhost:8333/%(bucket)' ls) - if [[ $(echo "$bucket_list" | tail -1 | awk '{print $3}') != 's3://profiles' ]]; then + if ! echo "$bucket_list" | grep -q "s3://profiles"; then apply_config_changes_profiles=0 # Only touch if no existing profiles config is found if ! grep -q "filestore.profiles-backend" $SENTRY_CONFIG_YML; then From 9b4f9ea82e599e51c487178b2c829c0f5b8ad8d0 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sat, 6 Dec 2025 07:09:34 +0700 Subject: [PATCH 288/305] ref: migrate to uv (#4061) * ref: migrate to uv * chore: remove main.py * fix: run pytest using uv * fix: pin Python and uv version * fix: extra spaces * ref: remove setup-python --- .github/workflows/fast-revert.yml | 4 +- .github/workflows/pre-commit.yml | 6 +- .github/workflows/release.yml | 8 +- .github/workflows/shellcheck.yml | 2 +- .github/workflows/test.yml | 4 +- .gitignore | 3 - .python-version | 1 + action.yaml | 19 +- pyproject.toml | 19 + requirements-dev.txt | 8 - uv.lock | 630 ++++++++++++++++++++++++++++++ 11 files changed, 678 insertions(+), 26 deletions(-) create mode 100644 .python-version create mode 100644 pyproject.toml delete mode 100644 requirements-dev.txt create mode 100644 uv.lock diff --git a/.github/workflows/fast-revert.yml b/.github/workflows/fast-revert.yml index 7a52386f0ab..8c7b7953ea4 100644 --- a/.github/workflows/fast-revert.yml +++ b/.github/workflows/fast-revert.yml @@ -19,10 +19,10 @@ jobs: if: | github.event_name == 'workflow_dispatch' || github.event.label.name == 'Trigger: Revert' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: token: ${{ secrets.BUMP_SENTRY_TOKEN }} - - uses: getsentry/action-fast-revert@v2.0.1 + - uses: getsentry/action-fast-revert@35b4b6c1f8f91b5911159568b3b15e531b5b8174 # v2.0.1 with: pr: ${{ github.event.number || github.event.inputs.pr }} co_authored_by: ${{ github.event.inputs.co_authored_by || format('{0} <{1}+{0}@users.noreply.github.com>', github.event.sender.login, github.event.sender.id) }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 53dfb67c6e4..5d8ca4adee9 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -12,8 +12,8 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: 3.x - - uses: pre-commit/action@v3.0.1 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a6c10d29fe3..3b92906be2b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,13 +27,13 @@ jobs: with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} - - uses: actions/checkout@v6 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: token: ${{ steps.token.outputs.token }} fetch-depth: 0 - name: Prepare release id: prepare-release - uses: getsentry/action-prepare-release@v1 + uses: getsentry/action-prepare-release@3cea80dc3938c0baf5ec4ce752ecb311f8780cdc # v1.6.4 env: GITHUB_TOKEN: ${{ steps.token.outputs.token }} with: @@ -48,10 +48,10 @@ jobs: name: Create release on self-hosted dogfood instance needs: release steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - - uses: getsentry/action-release@v3 + - uses: getsentry/action-release@128c5058bbbe93c8e02147fe0a9c713f166259a6 # v3.4.0 env: SENTRY_ORG: self-hosted SENTRY_PROJECT: installer diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 8e991d8b9f2..a712b50fc43 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Repository checkout - uses: actions/checkout@v6 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fed6749de15..57948e1d0ec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: name: ${{ matrix.os == 'ubuntu-24.04-arm' && 'unit tests (arm64)' || 'unit tests' }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Get Compose uses: ./get-compose-action @@ -56,7 +56,7 @@ jobs: CONTAINER_ENGINE_PODMAN: ${{ matrix.container_engine == 'podman' && '1' || '0' }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install Podman if: matrix.container_engine == 'podman' diff --git a/.gitignore b/.gitignore index 26d3ff590b1..98550a3c2bb 100644 --- a/.gitignore +++ b/.gitignore @@ -69,9 +69,6 @@ target/ # Ipython Notebook .ipynb_checkpoints -# pyenv -.python-version - # https://docs.docker.com/compose/extends/ docker-compose.override.yml diff --git a/.python-version b/.python-version new file mode 100644 index 00000000000..e4fba218358 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/action.yaml b/action.yaml index 89f1dd92692..82d1816fdb8 100644 --- a/action.yaml +++ b/action.yaml @@ -51,11 +51,24 @@ runs: sudo rm -rf /usr/share/dotnet /usr/share/doc/dotnet-* df -h + - name: Setup uv + uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 + with: + working-directory: ${{ github.action_path }} + version: "0.9.15" + # we just cache the venv-dir directly in action-setup-venv + enable-cache: false + + - uses: getsentry/action-setup-venv@0958463ee0e02b9e8aa8f8e031afae1f84b80881 # v3.0.0 + with: + cache-dependency-path: uv.lock + install-cmd: uv sync --frozen --active + - name: Setup dev environment shell: bash run: | cd ${{ github.action_path }} - pip install -r requirements-dev.txt + echo "PY_COLORS=1" >> "$GITHUB_ENV" ### pytest-sentry configuration ### if [ "$GITHUB_REPOSITORY" = "getsentry/self-hosted" ]; then @@ -191,7 +204,7 @@ runs: - name: Upload coverage to Codecov if: inputs.CODECOV_TOKEN continue-on-error: true - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 with: directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} @@ -200,7 +213,7 @@ runs: - name: Upload test results to Codecov if: inputs.CODECOV_TOKEN && !cancelled() continue-on-error: true - uses: codecov/test-results-action@v1 + uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1 with: directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000000..692d5582c57 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "sentry-self-hosted" +version = "0.1.0" +description = "Sentry, feature-complete and packaged up for low-volume deployments and proofs-of-concept." +readme = "README.md" +requires-python = ">=3.11" +dependencies = [] + +[dependency-groups] +dev = [ + "beautifulsoup4>=4.7.1", + "cryptography>=43.0.3", + "httpx>=0.25.2", + "pytest>=8.0.0", + "pytest-cov>=4.1.0", + "pytest-rerunfailures>=11.0", + "pytest-sentry>=0.1.11", + "sentry-sdk>=2.4.0,<3.0.0", +] diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 97d735ef800..00000000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,8 +0,0 @@ -sentry-sdk>=2.4.0,<3.0.0 -pytest>=8.0.0 -pytest-cov>=4.1.0 -pytest-rerunfailures>=11.0 -pytest-sentry>=0.1.11 -httpx>=0.25.2 -beautifulsoup4>=4.7.1 -cryptography>=43.0.3 diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000000..d7b7e9eed9d --- /dev/null +++ b/uv.lock @@ -0,0 +1,630 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/26/4a96807b193b011588099c3b5c89fbb05294e5b90e71018e065465f34eb6/coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c", size = 819341, upload-time = "2025-11-18T13:34:20.766Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/0c/0dfe7f0487477d96432e4815537263363fb6dd7289743a796e8e51eabdf2/coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f", size = 217535, upload-time = "2025-11-18T13:32:08.812Z" }, + { url = "https://files.pythonhosted.org/packages/9b/f5/f9a4a053a5bbff023d3bec259faac8f11a1e5a6479c2ccf586f910d8dac7/coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3", size = 218044, upload-time = "2025-11-18T13:32:10.329Z" }, + { url = "https://files.pythonhosted.org/packages/95/c5/84fc3697c1fa10cd8571919bf9693f693b7373278daaf3b73e328d502bc8/coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e", size = 248440, upload-time = "2025-11-18T13:32:12.536Z" }, + { url = "https://files.pythonhosted.org/packages/f4/36/2d93fbf6a04670f3874aed397d5a5371948a076e3249244a9e84fb0e02d6/coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7", size = 250361, upload-time = "2025-11-18T13:32:13.852Z" }, + { url = "https://files.pythonhosted.org/packages/5d/49/66dc65cc456a6bfc41ea3d0758c4afeaa4068a2b2931bf83be6894cf1058/coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245", size = 252472, upload-time = "2025-11-18T13:32:15.068Z" }, + { url = "https://files.pythonhosted.org/packages/35/1f/ebb8a18dffd406db9fcd4b3ae42254aedcaf612470e8712f12041325930f/coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b", size = 248592, upload-time = "2025-11-18T13:32:16.328Z" }, + { url = "https://files.pythonhosted.org/packages/da/a8/67f213c06e5ea3b3d4980df7dc344d7fea88240b5fe878a5dcbdfe0e2315/coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64", size = 250167, upload-time = "2025-11-18T13:32:17.687Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/e52aef68154164ea40cc8389c120c314c747fe63a04b013a5782e989b77f/coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742", size = 248238, upload-time = "2025-11-18T13:32:19.2Z" }, + { url = "https://files.pythonhosted.org/packages/1f/a4/4d88750bcf9d6d66f77865e5a05a20e14db44074c25fd22519777cb69025/coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c", size = 247964, upload-time = "2025-11-18T13:32:21.027Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6b/b74693158899d5b47b0bf6238d2c6722e20ba749f86b74454fac0696bb00/coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984", size = 248862, upload-time = "2025-11-18T13:32:22.304Z" }, + { url = "https://files.pythonhosted.org/packages/18/de/6af6730227ce0e8ade307b1cc4a08e7f51b419a78d02083a86c04ccceb29/coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6", size = 220033, upload-time = "2025-11-18T13:32:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/e7f63021a7c4fe20994359fcdeae43cbef4a4d0ca36a5a1639feeea5d9e1/coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4", size = 220966, upload-time = "2025-11-18T13:32:25.599Z" }, + { url = "https://files.pythonhosted.org/packages/77/e8/deae26453f37c20c3aa0c4433a1e32cdc169bf415cce223a693117aa3ddd/coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc", size = 219637, upload-time = "2025-11-18T13:32:27.265Z" }, + { url = "https://files.pythonhosted.org/packages/02/bf/638c0427c0f0d47638242e2438127f3c8ee3cfc06c7fdeb16778ed47f836/coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647", size = 217704, upload-time = "2025-11-18T13:32:28.906Z" }, + { url = "https://files.pythonhosted.org/packages/08/e1/706fae6692a66c2d6b871a608bbde0da6281903fa0e9f53a39ed441da36a/coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736", size = 218064, upload-time = "2025-11-18T13:32:30.161Z" }, + { url = "https://files.pythonhosted.org/packages/a9/8b/eb0231d0540f8af3ffda39720ff43cb91926489d01524e68f60e961366e4/coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60", size = 249560, upload-time = "2025-11-18T13:32:31.835Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a1/67fb52af642e974d159b5b379e4d4c59d0ebe1288677fbd04bbffe665a82/coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8", size = 252318, upload-time = "2025-11-18T13:32:33.178Z" }, + { url = "https://files.pythonhosted.org/packages/41/e5/38228f31b2c7665ebf9bdfdddd7a184d56450755c7e43ac721c11a4b8dab/coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f", size = 253403, upload-time = "2025-11-18T13:32:34.45Z" }, + { url = "https://files.pythonhosted.org/packages/ec/4b/df78e4c8188f9960684267c5a4897836f3f0f20a20c51606ee778a1d9749/coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70", size = 249984, upload-time = "2025-11-18T13:32:35.747Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/bb163933d195a345c6f63eab9e55743413d064c291b6220df754075c2769/coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0", size = 251339, upload-time = "2025-11-18T13:32:37.352Z" }, + { url = "https://files.pythonhosted.org/packages/15/40/c9b29cdb8412c837cdcbc2cfa054547dd83affe6cbbd4ce4fdb92b6ba7d1/coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068", size = 249489, upload-time = "2025-11-18T13:32:39.212Z" }, + { url = "https://files.pythonhosted.org/packages/c8/da/b3131e20ba07a0de4437a50ef3b47840dfabf9293675b0cd5c2c7f66dd61/coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b", size = 249070, upload-time = "2025-11-18T13:32:40.598Z" }, + { url = "https://files.pythonhosted.org/packages/70/81/b653329b5f6302c08d683ceff6785bc60a34be9ae92a5c7b63ee7ee7acec/coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937", size = 250929, upload-time = "2025-11-18T13:32:42.915Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/250ac3bca9f252a5fb1338b5ad01331ebb7b40223f72bef5b1b2cb03aa64/coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa", size = 220241, upload-time = "2025-11-18T13:32:44.665Z" }, + { url = "https://files.pythonhosted.org/packages/64/1c/77e79e76d37ce83302f6c21980b45e09f8aa4551965213a10e62d71ce0ab/coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a", size = 221051, upload-time = "2025-11-18T13:32:46.008Z" }, + { url = "https://files.pythonhosted.org/packages/31/f5/641b8a25baae564f9e52cac0e2667b123de961985709a004e287ee7663cc/coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c", size = 219692, upload-time = "2025-11-18T13:32:47.372Z" }, + { url = "https://files.pythonhosted.org/packages/b8/14/771700b4048774e48d2c54ed0c674273702713c9ee7acdfede40c2666747/coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941", size = 217725, upload-time = "2025-11-18T13:32:49.22Z" }, + { url = "https://files.pythonhosted.org/packages/17/a7/3aa4144d3bcb719bf67b22d2d51c2d577bf801498c13cb08f64173e80497/coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a", size = 218098, upload-time = "2025-11-18T13:32:50.78Z" }, + { url = "https://files.pythonhosted.org/packages/fc/9c/b846bbc774ff81091a12a10203e70562c91ae71badda00c5ae5b613527b1/coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d", size = 249093, upload-time = "2025-11-18T13:32:52.554Z" }, + { url = "https://files.pythonhosted.org/packages/76/b6/67d7c0e1f400b32c883e9342de4a8c2ae7c1a0b57c5de87622b7262e2309/coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211", size = 251686, upload-time = "2025-11-18T13:32:54.862Z" }, + { url = "https://files.pythonhosted.org/packages/cc/75/b095bd4b39d49c3be4bffbb3135fea18a99a431c52dd7513637c0762fecb/coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d", size = 252930, upload-time = "2025-11-18T13:32:56.417Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f3/466f63015c7c80550bead3093aacabf5380c1220a2a93c35d374cae8f762/coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c", size = 249296, upload-time = "2025-11-18T13:32:58.074Z" }, + { url = "https://files.pythonhosted.org/packages/27/86/eba2209bf2b7e28c68698fc13437519a295b2d228ba9e0ec91673e09fa92/coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9", size = 251068, upload-time = "2025-11-18T13:32:59.646Z" }, + { url = "https://files.pythonhosted.org/packages/ec/55/ca8ae7dbba962a3351f18940b359b94c6bafdd7757945fdc79ec9e452dc7/coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0", size = 249034, upload-time = "2025-11-18T13:33:01.481Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d7/39136149325cad92d420b023b5fd900dabdd1c3a0d1d5f148ef4a8cedef5/coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508", size = 248853, upload-time = "2025-11-18T13:33:02.935Z" }, + { url = "https://files.pythonhosted.org/packages/fe/b6/76e1add8b87ef60e00643b0b7f8f7bb73d4bf5249a3be19ebefc5793dd25/coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc", size = 250619, upload-time = "2025-11-18T13:33:04.336Z" }, + { url = "https://files.pythonhosted.org/packages/95/87/924c6dc64f9203f7a3c1832a6a0eee5a8335dbe5f1bdadcc278d6f1b4d74/coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8", size = 220261, upload-time = "2025-11-18T13:33:06.493Z" }, + { url = "https://files.pythonhosted.org/packages/91/77/dd4aff9af16ff776bf355a24d87eeb48fc6acde54c907cc1ea89b14a8804/coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07", size = 221072, upload-time = "2025-11-18T13:33:07.926Z" }, + { url = "https://files.pythonhosted.org/packages/70/49/5c9dc46205fef31b1b226a6e16513193715290584317fd4df91cdaf28b22/coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc", size = 219702, upload-time = "2025-11-18T13:33:09.631Z" }, + { url = "https://files.pythonhosted.org/packages/9b/62/f87922641c7198667994dd472a91e1d9b829c95d6c29529ceb52132436ad/coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87", size = 218420, upload-time = "2025-11-18T13:33:11.153Z" }, + { url = "https://files.pythonhosted.org/packages/85/dd/1cc13b2395ef15dbb27d7370a2509b4aee77890a464fb35d72d428f84871/coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6", size = 218773, upload-time = "2025-11-18T13:33:12.569Z" }, + { url = "https://files.pythonhosted.org/packages/74/40/35773cc4bb1e9d4658d4fb669eb4195b3151bef3bbd6f866aba5cd5dac82/coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7", size = 260078, upload-time = "2025-11-18T13:33:14.037Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ee/231bb1a6ffc2905e396557585ebc6bdc559e7c66708376d245a1f1d330fc/coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560", size = 262144, upload-time = "2025-11-18T13:33:15.601Z" }, + { url = "https://files.pythonhosted.org/packages/28/be/32f4aa9f3bf0b56f3971001b56508352c7753915345d45fab4296a986f01/coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12", size = 264574, upload-time = "2025-11-18T13:33:17.354Z" }, + { url = "https://files.pythonhosted.org/packages/68/7c/00489fcbc2245d13ab12189b977e0cf06ff3351cb98bc6beba8bd68c5902/coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296", size = 259298, upload-time = "2025-11-18T13:33:18.958Z" }, + { url = "https://files.pythonhosted.org/packages/96/b4/f0760d65d56c3bea95b449e02570d4abd2549dc784bf39a2d4721a2d8ceb/coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507", size = 262150, upload-time = "2025-11-18T13:33:20.644Z" }, + { url = "https://files.pythonhosted.org/packages/c5/71/9a9314df00f9326d78c1e5a910f520d599205907432d90d1c1b7a97aa4b1/coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d", size = 259763, upload-time = "2025-11-18T13:33:22.189Z" }, + { url = "https://files.pythonhosted.org/packages/10/34/01a0aceed13fbdf925876b9a15d50862eb8845454301fe3cdd1df08b2182/coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2", size = 258653, upload-time = "2025-11-18T13:33:24.239Z" }, + { url = "https://files.pythonhosted.org/packages/8d/04/81d8fd64928acf1574bbb0181f66901c6c1c6279c8ccf5f84259d2c68ae9/coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455", size = 260856, upload-time = "2025-11-18T13:33:26.365Z" }, + { url = "https://files.pythonhosted.org/packages/f2/76/fa2a37bfaeaf1f766a2d2360a25a5297d4fb567098112f6517475eee120b/coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d", size = 220936, upload-time = "2025-11-18T13:33:28.165Z" }, + { url = "https://files.pythonhosted.org/packages/f9/52/60f64d932d555102611c366afb0eb434b34266b1d9266fc2fe18ab641c47/coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c", size = 222001, upload-time = "2025-11-18T13:33:29.656Z" }, + { url = "https://files.pythonhosted.org/packages/77/df/c303164154a5a3aea7472bf323b7c857fed93b26618ed9fc5c2955566bb0/coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d", size = 220273, upload-time = "2025-11-18T13:33:31.415Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2e/fc12db0883478d6e12bbd62d481210f0c8daf036102aa11434a0c5755825/coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92", size = 217777, upload-time = "2025-11-18T13:33:32.86Z" }, + { url = "https://files.pythonhosted.org/packages/1f/c1/ce3e525d223350c6ec16b9be8a057623f54226ef7f4c2fee361ebb6a02b8/coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360", size = 218100, upload-time = "2025-11-18T13:33:34.532Z" }, + { url = "https://files.pythonhosted.org/packages/15/87/113757441504aee3808cb422990ed7c8bcc2d53a6779c66c5adef0942939/coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac", size = 249151, upload-time = "2025-11-18T13:33:36.135Z" }, + { url = "https://files.pythonhosted.org/packages/d9/1d/9529d9bd44049b6b05bb319c03a3a7e4b0a8a802d28fa348ad407e10706d/coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d", size = 251667, upload-time = "2025-11-18T13:33:37.996Z" }, + { url = "https://files.pythonhosted.org/packages/11/bb/567e751c41e9c03dc29d3ce74b8c89a1e3396313e34f255a2a2e8b9ebb56/coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c", size = 253003, upload-time = "2025-11-18T13:33:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/e4/b3/c2cce2d8526a02fb9e9ca14a263ca6fc074449b33a6afa4892838c903528/coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434", size = 249185, upload-time = "2025-11-18T13:33:42.086Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a7/967f93bb66e82c9113c66a8d0b65ecf72fc865adfba5a145f50c7af7e58d/coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc", size = 251025, upload-time = "2025-11-18T13:33:43.634Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/f2f6f56337bc1af465d5b2dc1ee7ee2141b8b9272f3bf6213fcbc309a836/coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc", size = 248979, upload-time = "2025-11-18T13:33:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7a/bf4209f45a4aec09d10a01a57313a46c0e0e8f4c55ff2965467d41a92036/coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e", size = 248800, upload-time = "2025-11-18T13:33:47.546Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b7/1e01b8696fb0521810f60c5bbebf699100d6754183e6cc0679bf2ed76531/coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17", size = 250460, upload-time = "2025-11-18T13:33:49.537Z" }, + { url = "https://files.pythonhosted.org/packages/71/ae/84324fb9cb46c024760e706353d9b771a81b398d117d8c1fe010391c186f/coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933", size = 220533, upload-time = "2025-11-18T13:33:51.16Z" }, + { url = "https://files.pythonhosted.org/packages/e2/71/1033629deb8460a8f97f83e6ac4ca3b93952e2b6f826056684df8275e015/coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe", size = 221348, upload-time = "2025-11-18T13:33:52.776Z" }, + { url = "https://files.pythonhosted.org/packages/0a/5f/ac8107a902f623b0c251abdb749be282dc2ab61854a8a4fcf49e276fce2f/coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d", size = 219922, upload-time = "2025-11-18T13:33:54.316Z" }, + { url = "https://files.pythonhosted.org/packages/79/6e/f27af2d4da367f16077d21ef6fe796c874408219fa6dd3f3efe7751bd910/coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d", size = 218511, upload-time = "2025-11-18T13:33:56.343Z" }, + { url = "https://files.pythonhosted.org/packages/67/dd/65fd874aa460c30da78f9d259400d8e6a4ef457d61ab052fd248f0050558/coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03", size = 218771, upload-time = "2025-11-18T13:33:57.966Z" }, + { url = "https://files.pythonhosted.org/packages/55/e0/7c6b71d327d8068cb79c05f8f45bf1b6145f7a0de23bbebe63578fe5240a/coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9", size = 260151, upload-time = "2025-11-18T13:33:59.597Z" }, + { url = "https://files.pythonhosted.org/packages/49/ce/4697457d58285b7200de6b46d606ea71066c6e674571a946a6ea908fb588/coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6", size = 262257, upload-time = "2025-11-18T13:34:01.166Z" }, + { url = "https://files.pythonhosted.org/packages/2f/33/acbc6e447aee4ceba88c15528dbe04a35fb4d67b59d393d2e0d6f1e242c1/coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339", size = 264671, upload-time = "2025-11-18T13:34:02.795Z" }, + { url = "https://files.pythonhosted.org/packages/87/ec/e2822a795c1ed44d569980097be839c5e734d4c0c1119ef8e0a073496a30/coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e", size = 259231, upload-time = "2025-11-18T13:34:04.397Z" }, + { url = "https://files.pythonhosted.org/packages/72/c5/a7ec5395bb4a49c9b7ad97e63f0c92f6bf4a9e006b1393555a02dae75f16/coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13", size = 262137, upload-time = "2025-11-18T13:34:06.068Z" }, + { url = "https://files.pythonhosted.org/packages/67/0c/02c08858b764129f4ecb8e316684272972e60777ae986f3865b10940bdd6/coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f", size = 259745, upload-time = "2025-11-18T13:34:08.04Z" }, + { url = "https://files.pythonhosted.org/packages/5a/04/4fd32b7084505f3829a8fe45c1a74a7a728cb251aaadbe3bec04abcef06d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1", size = 258570, upload-time = "2025-11-18T13:34:09.676Z" }, + { url = "https://files.pythonhosted.org/packages/48/35/2365e37c90df4f5342c4fa202223744119fe31264ee2924f09f074ea9b6d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b", size = 260899, upload-time = "2025-11-18T13:34:11.259Z" }, + { url = "https://files.pythonhosted.org/packages/05/56/26ab0464ca733fa325e8e71455c58c1c374ce30f7c04cebb88eabb037b18/coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a", size = 221313, upload-time = "2025-11-18T13:34:12.863Z" }, + { url = "https://files.pythonhosted.org/packages/da/1c/017a3e1113ed34d998b27d2c6dba08a9e7cb97d362f0ec988fcd873dcf81/coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291", size = 222423, upload-time = "2025-11-18T13:34:15.14Z" }, + { url = "https://files.pythonhosted.org/packages/4c/36/bcc504fdd5169301b52568802bb1b9cdde2e27a01d39fbb3b4b508ab7c2c/coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384", size = 220459, upload-time = "2025-11-18T13:34:17.222Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "cryptography" +version = "46.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, + { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, + { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, + { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, + { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, + { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, + { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, + { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, + { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, + { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e2/a510aa736755bffa9d2f75029c229111a1d02f8ecd5de03078f4c18d91a3/cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217", size = 7158012, upload-time = "2025-10-15T23:17:19.982Z" }, + { url = "https://files.pythonhosted.org/packages/73/dc/9aa866fbdbb95b02e7f9d086f1fccfeebf8953509b87e3f28fff927ff8a0/cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5", size = 4288728, upload-time = "2025-10-15T23:17:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/c5/fd/bc1daf8230eaa075184cbbf5f8cd00ba9db4fd32d63fb83da4671b72ed8a/cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715", size = 4435078, upload-time = "2025-10-15T23:17:23.042Z" }, + { url = "https://files.pythonhosted.org/packages/82/98/d3bd5407ce4c60017f8ff9e63ffee4200ab3e23fe05b765cab805a7db008/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54", size = 4293460, upload-time = "2025-10-15T23:17:24.885Z" }, + { url = "https://files.pythonhosted.org/packages/26/e9/e23e7900983c2b8af7a08098db406cf989d7f09caea7897e347598d4cd5b/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459", size = 3995237, upload-time = "2025-10-15T23:17:26.449Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/af68c509d4a138cfe299d0d7ddb14afba15233223ebd933b4bbdbc7155d3/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422", size = 4967344, upload-time = "2025-10-15T23:17:28.06Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e3/8643d077c53868b681af077edf6b3cb58288b5423610f21c62aadcbe99f4/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7", size = 4466564, upload-time = "2025-10-15T23:17:29.665Z" }, + { url = "https://files.pythonhosted.org/packages/0e/43/c1e8726fa59c236ff477ff2b5dc071e54b21e5a1e51aa2cee1676f1c986f/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044", size = 4292415, upload-time = "2025-10-15T23:17:31.686Z" }, + { url = "https://files.pythonhosted.org/packages/42/f9/2f8fefdb1aee8a8e3256a0568cffc4e6d517b256a2fe97a029b3f1b9fe7e/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665", size = 4931457, upload-time = "2025-10-15T23:17:33.478Z" }, + { url = "https://files.pythonhosted.org/packages/79/30/9b54127a9a778ccd6d27c3da7563e9f2d341826075ceab89ae3b41bf5be2/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3", size = 4466074, upload-time = "2025-10-15T23:17:35.158Z" }, + { url = "https://files.pythonhosted.org/packages/ac/68/b4f4a10928e26c941b1b6a179143af9f4d27d88fe84a6a3c53592d2e76bf/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20", size = 4420569, upload-time = "2025-10-15T23:17:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/a3/49/3746dab4c0d1979888f125226357d3262a6dd40e114ac29e3d2abdf1ec55/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de", size = 4681941, upload-time = "2025-10-15T23:17:39.236Z" }, + { url = "https://files.pythonhosted.org/packages/fd/30/27654c1dbaf7e4a3531fa1fc77986d04aefa4d6d78259a62c9dc13d7ad36/cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914", size = 3022339, upload-time = "2025-10-15T23:17:40.888Z" }, + { url = "https://files.pythonhosted.org/packages/f6/30/640f34ccd4d2a1bc88367b54b926b781b5a018d65f404d409aba76a84b1c/cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db", size = 3494315, upload-time = "2025-10-15T23:17:42.769Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8b/88cc7e3bd0a8e7b861f26981f7b820e1f46aa9d26cc482d0feba0ecb4919/cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21", size = 2919331, upload-time = "2025-10-15T23:17:44.468Z" }, + { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, + { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, + { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, + { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, + { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, + { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, + { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, + { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, + { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, + { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, + { url = "https://files.pythonhosted.org/packages/06/8a/e60e46adab4362a682cf142c7dcb5bf79b782ab2199b0dcb81f55970807f/cryptography-46.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ce938a99998ed3c8aa7e7272dca1a610401ede816d36d0693907d863b10d9ea", size = 3698132, upload-time = "2025-10-15T23:18:17.056Z" }, + { url = "https://files.pythonhosted.org/packages/da/38/f59940ec4ee91e93d3311f7532671a5cef5570eb04a144bf203b58552d11/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:191bb60a7be5e6f54e30ba16fdfae78ad3a342a0599eb4193ba88e3f3d6e185b", size = 4243992, upload-time = "2025-10-15T23:18:18.695Z" }, + { url = "https://files.pythonhosted.org/packages/b0/0c/35b3d92ddebfdfda76bb485738306545817253d0a3ded0bfe80ef8e67aa5/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c70cc23f12726be8f8bc72e41d5065d77e4515efae3690326764ea1b07845cfb", size = 4409944, upload-time = "2025-10-15T23:18:20.597Z" }, + { url = "https://files.pythonhosted.org/packages/99/55/181022996c4063fc0e7666a47049a1ca705abb9c8a13830f074edb347495/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:9394673a9f4de09e28b5356e7fff97d778f8abad85c9d5ac4a4b7e25a0de7717", size = 4242957, upload-time = "2025-10-15T23:18:22.18Z" }, + { url = "https://files.pythonhosted.org/packages/ba/af/72cd6ef29f9c5f731251acadaeb821559fe25f10852f44a63374c9ca08c1/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94cd0549accc38d1494e1f8de71eca837d0509d0d44bf11d158524b0e12cebf9", size = 4409447, upload-time = "2025-10-15T23:18:24.209Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c3/e90f4a4feae6410f914f8ebac129b9ae7a8c92eb60a638012dde42030a9d/cryptography-46.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6b5063083824e5509fdba180721d55909ffacccc8adbec85268b48439423d78c", size = 3438528, upload-time = "2025-10-15T23:18:26.227Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-rerunfailures" +version = "16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/04/71e9520551fc8fe2cf5c1a1842e4e600265b0815f2016b7c27ec85688682/pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e", size = 30889, upload-time = "2025-10-10T07:06:01.238Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/54/60eabb34445e3db3d3d874dc1dfa72751bfec3265bd611cb13c8b290adea/pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86", size = 14093, upload-time = "2025-10-10T07:06:00.019Z" }, +] + +[[package]] +name = "pytest-sentry" +version = "0.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "sentry-sdk" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/44/dbe8420883c6bd89247339f521580ae9c91838bfee0159d5183161063483/pytest_sentry-0.3.3.tar.gz", hash = "sha256:c14ff1b0a00fb62fb83c9523fe03ee00896ac61829a3b20a7a57b1d4524e3336", size = 9346, upload-time = "2025-02-24T18:20:28.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/4f/ebacd5c58186bad0f61312771ed344448dd4e9967ef627f31b5b7ac85d92/pytest_sentry-0.3.3-py3-none-any.whl", hash = "sha256:acf2b76cf5eb3213371f5d29868dab0e35e0653012d5e87af9da82f043cdfb87", size = 8514, upload-time = "2025-02-24T18:20:27.042Z" }, +] + +[[package]] +name = "sentry-sdk" +version = "2.46.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/d7/c140a5837649e2bf2ec758494fde1d9a016c76777eab64e75ef38d685bbb/sentry_sdk-2.46.0.tar.gz", hash = "sha256:91821a23460725734b7741523021601593f35731808afc0bb2ba46c27b8acd91", size = 374761, upload-time = "2025-11-24T09:34:13.932Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/b6/ce7c502a366f4835b1f9c057753f6989a92d3c70cbadb168193f5fb7499b/sentry_sdk-2.46.0-py2.py3-none-any.whl", hash = "sha256:4eeeb60198074dff8d066ea153fa6f241fef1668c10900ea53a4200abc8da9b1", size = 406266, upload-time = "2025-11-24T09:34:12.114Z" }, +] + +[[package]] +name = "sentry-self-hosted" +version = "0.1.0" +source = { virtual = "." } + +[package.dev-dependencies] +dev = [ + { name = "beautifulsoup4" }, + { name = "cryptography" }, + { name = "httpx" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-rerunfailures" }, + { name = "pytest-sentry" }, + { name = "sentry-sdk" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +dev = [ + { name = "beautifulsoup4", specifier = ">=4.7.1" }, + { name = "cryptography", specifier = ">=43.0.3" }, + { name = "httpx", specifier = ">=0.25.2" }, + { name = "pytest", specifier = ">=8.0.0" }, + { name = "pytest-cov", specifier = ">=4.1.0" }, + { name = "pytest-rerunfailures", specifier = ">=11.0" }, + { name = "pytest-sentry", specifier = ">=0.1.11" }, + { name = "sentry-sdk", specifier = ">=2.4.0,<3.0.0" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, +] + +[[package]] +name = "tomli" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, + { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, + { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, + { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, + { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, + { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, + { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, + { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, + { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, + { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, + { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, + { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, + { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" }, + { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" }, + { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, + { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, + { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, + { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, + { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, + { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, + { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, + { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, + { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, + { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, + { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, + { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, + { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, + { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, + { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, + { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, + { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, + { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, + { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, + { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "wrapt" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/60/553997acf3939079dab022e37b67b1904b5b0cc235503226898ba573b10c/wrapt-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e17283f533a0d24d6e5429a7d11f250a58d28b4ae5186f8f47853e3e70d2590", size = 77480, upload-time = "2025-11-07T00:43:30.573Z" }, + { url = "https://files.pythonhosted.org/packages/2d/50/e5b3d30895d77c52105c6d5cbf94d5b38e2a3dd4a53d22d246670da98f7c/wrapt-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85df8d92158cb8f3965aecc27cf821461bb5f40b450b03facc5d9f0d4d6ddec6", size = 60690, upload-time = "2025-11-07T00:43:31.594Z" }, + { url = "https://files.pythonhosted.org/packages/f0/40/660b2898703e5cbbb43db10cdefcc294274458c3ca4c68637c2b99371507/wrapt-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1be685ac7700c966b8610ccc63c3187a72e33cab53526a27b2a285a662cd4f7", size = 61578, upload-time = "2025-11-07T00:43:32.918Z" }, + { url = "https://files.pythonhosted.org/packages/5b/36/825b44c8a10556957bc0c1d84c7b29a40e05fcf1873b6c40aa9dbe0bd972/wrapt-2.0.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:df0b6d3b95932809c5b3fecc18fda0f1e07452d05e2662a0b35548985f256e28", size = 114115, upload-time = "2025-11-07T00:43:35.605Z" }, + { url = "https://files.pythonhosted.org/packages/83/73/0a5d14bb1599677304d3c613a55457d34c344e9b60eda8a737c2ead7619e/wrapt-2.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4da7384b0e5d4cae05c97cd6f94faaf78cc8b0f791fc63af43436d98c4ab37bb", size = 116157, upload-time = "2025-11-07T00:43:37.058Z" }, + { url = "https://files.pythonhosted.org/packages/01/22/1c158fe763dbf0a119f985d945711d288994fe5514c0646ebe0eb18b016d/wrapt-2.0.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ec65a78fbd9d6f083a15d7613b2800d5663dbb6bb96003899c834beaa68b242c", size = 112535, upload-time = "2025-11-07T00:43:34.138Z" }, + { url = "https://files.pythonhosted.org/packages/5c/28/4f16861af67d6de4eae9927799b559c20ebdd4fe432e89ea7fe6fcd9d709/wrapt-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7de3cc939be0e1174969f943f3b44e0d79b6f9a82198133a5b7fc6cc92882f16", size = 115404, upload-time = "2025-11-07T00:43:39.214Z" }, + { url = "https://files.pythonhosted.org/packages/a0/8b/7960122e625fad908f189b59c4aae2d50916eb4098b0fb2819c5a177414f/wrapt-2.0.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:fb1a5b72cbd751813adc02ef01ada0b0d05d3dcbc32976ce189a1279d80ad4a2", size = 111802, upload-time = "2025-11-07T00:43:40.476Z" }, + { url = "https://files.pythonhosted.org/packages/3e/73/7881eee5ac31132a713ab19a22c9e5f1f7365c8b1df50abba5d45b781312/wrapt-2.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3fa272ca34332581e00bf7773e993d4f632594eb2d1b0b162a9038df0fd971dd", size = 113837, upload-time = "2025-11-07T00:43:42.921Z" }, + { url = "https://files.pythonhosted.org/packages/45/00/9499a3d14e636d1f7089339f96c4409bbc7544d0889f12264efa25502ae8/wrapt-2.0.1-cp311-cp311-win32.whl", hash = "sha256:fc007fdf480c77301ab1afdbb6ab22a5deee8885f3b1ed7afcb7e5e84a0e27be", size = 58028, upload-time = "2025-11-07T00:43:47.369Z" }, + { url = "https://files.pythonhosted.org/packages/70/5d/8f3d7eea52f22638748f74b102e38fdf88cb57d08ddeb7827c476a20b01b/wrapt-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:47434236c396d04875180171ee1f3815ca1eada05e24a1ee99546320d54d1d1b", size = 60385, upload-time = "2025-11-07T00:43:44.34Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/32195e57a8209003587bbbad44d5922f13e0ced2a493bb46ca882c5b123d/wrapt-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:837e31620e06b16030b1d126ed78e9383815cbac914693f54926d816d35d8edf", size = 58893, upload-time = "2025-11-07T00:43:46.161Z" }, + { url = "https://files.pythonhosted.org/packages/cb/73/8cb252858dc8254baa0ce58ce382858e3a1cf616acebc497cb13374c95c6/wrapt-2.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1fdbb34da15450f2b1d735a0e969c24bdb8d8924892380126e2a293d9902078c", size = 78129, upload-time = "2025-11-07T00:43:48.852Z" }, + { url = "https://files.pythonhosted.org/packages/19/42/44a0db2108526ee6e17a5ab72478061158f34b08b793df251d9fbb9a7eb4/wrapt-2.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3d32794fe940b7000f0519904e247f902f0149edbe6316c710a8562fb6738841", size = 61205, upload-time = "2025-11-07T00:43:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/4d/8a/5b4b1e44b791c22046e90d9b175f9a7581a8cc7a0debbb930f81e6ae8e25/wrapt-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:386fb54d9cd903ee0012c09291336469eb7b244f7183d40dc3e86a16a4bace62", size = 61692, upload-time = "2025-11-07T00:43:51.678Z" }, + { url = "https://files.pythonhosted.org/packages/11/53/3e794346c39f462bcf1f58ac0487ff9bdad02f9b6d5ee2dc84c72e0243b2/wrapt-2.0.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7b219cb2182f230676308cdcacd428fa837987b89e4b7c5c9025088b8a6c9faf", size = 121492, upload-time = "2025-11-07T00:43:55.017Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7e/10b7b0e8841e684c8ca76b462a9091c45d62e8f2de9c4b1390b690eadf16/wrapt-2.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:641e94e789b5f6b4822bb8d8ebbdfc10f4e4eae7756d648b717d980f657a9eb9", size = 123064, upload-time = "2025-11-07T00:43:56.323Z" }, + { url = "https://files.pythonhosted.org/packages/0e/d1/3c1e4321fc2f5ee7fd866b2d822aa89b84495f28676fd976c47327c5b6aa/wrapt-2.0.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe21b118b9f58859b5ebaa4b130dee18669df4bd111daad082b7beb8799ad16b", size = 117403, upload-time = "2025-11-07T00:43:53.258Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b0/d2f0a413cf201c8c2466de08414a15420a25aa83f53e647b7255cc2fab5d/wrapt-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:17fb85fa4abc26a5184d93b3efd2dcc14deb4b09edcdb3535a536ad34f0b4dba", size = 121500, upload-time = "2025-11-07T00:43:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/bd/45/bddb11d28ca39970a41ed48a26d210505120f925918592283369219f83cc/wrapt-2.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b89ef9223d665ab255ae42cc282d27d69704d94be0deffc8b9d919179a609684", size = 116299, upload-time = "2025-11-07T00:43:58.877Z" }, + { url = "https://files.pythonhosted.org/packages/81/af/34ba6dd570ef7a534e7eec0c25e2615c355602c52aba59413411c025a0cb/wrapt-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a453257f19c31b31ba593c30d997d6e5be39e3b5ad9148c2af5a7314061c63eb", size = 120622, upload-time = "2025-11-07T00:43:59.962Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3e/693a13b4146646fb03254636f8bafd20c621955d27d65b15de07ab886187/wrapt-2.0.1-cp312-cp312-win32.whl", hash = "sha256:3e271346f01e9c8b1130a6a3b0e11908049fe5be2d365a5f402778049147e7e9", size = 58246, upload-time = "2025-11-07T00:44:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/a7/36/715ec5076f925a6be95f37917b66ebbeaa1372d1862c2ccd7a751574b068/wrapt-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:2da620b31a90cdefa9cd0c2b661882329e2e19d1d7b9b920189956b76c564d75", size = 60492, upload-time = "2025-11-07T00:44:01.027Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3e/62451cd7d80f65cc125f2b426b25fbb6c514bf6f7011a0c3904fc8c8df90/wrapt-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:aea9c7224c302bc8bfc892b908537f56c430802560e827b75ecbde81b604598b", size = 58987, upload-time = "2025-11-07T00:44:02.095Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/41af4c46b5e498c90fc87981ab2972fbd9f0bccda597adb99d3d3441b94b/wrapt-2.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:47b0f8bafe90f7736151f61482c583c86b0693d80f075a58701dd1549b0010a9", size = 78132, upload-time = "2025-11-07T00:44:04.628Z" }, + { url = "https://files.pythonhosted.org/packages/1c/92/d68895a984a5ebbbfb175512b0c0aad872354a4a2484fbd5552e9f275316/wrapt-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cbeb0971e13b4bd81d34169ed57a6dda017328d1a22b62fda45e1d21dd06148f", size = 61211, upload-time = "2025-11-07T00:44:05.626Z" }, + { url = "https://files.pythonhosted.org/packages/e8/26/ba83dc5ae7cf5aa2b02364a3d9cf74374b86169906a1f3ade9a2d03cf21c/wrapt-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb7cffe572ad0a141a7886a1d2efa5bef0bf7fe021deeea76b3ab334d2c38218", size = 61689, upload-time = "2025-11-07T00:44:06.719Z" }, + { url = "https://files.pythonhosted.org/packages/cf/67/d7a7c276d874e5d26738c22444d466a3a64ed541f6ef35f740dbd865bab4/wrapt-2.0.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8d60527d1ecfc131426b10d93ab5d53e08a09c5fa0175f6b21b3252080c70a9", size = 121502, upload-time = "2025-11-07T00:44:09.557Z" }, + { url = "https://files.pythonhosted.org/packages/0f/6b/806dbf6dd9579556aab22fc92908a876636e250f063f71548a8660382184/wrapt-2.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c654eafb01afac55246053d67a4b9a984a3567c3808bb7df2f8de1c1caba2e1c", size = 123110, upload-time = "2025-11-07T00:44:10.64Z" }, + { url = "https://files.pythonhosted.org/packages/e5/08/cdbb965fbe4c02c5233d185d070cabed2ecc1f1e47662854f95d77613f57/wrapt-2.0.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:98d873ed6c8b4ee2418f7afce666751854d6d03e3c0ec2a399bb039cd2ae89db", size = 117434, upload-time = "2025-11-07T00:44:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d1/6aae2ce39db4cb5216302fa2e9577ad74424dfbe315bd6669725569e048c/wrapt-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9e850f5b7fc67af856ff054c71690d54fa940c3ef74209ad9f935b4f66a0233", size = 121533, upload-time = "2025-11-07T00:44:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/565abf57559fbe0a9155c29879ff43ce8bd28d2ca61033a3a3dd67b70794/wrapt-2.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e505629359cb5f751e16e30cf3f91a1d3ddb4552480c205947da415d597f7ac2", size = 116324, upload-time = "2025-11-07T00:44:13.28Z" }, + { url = "https://files.pythonhosted.org/packages/e1/e0/53ff5e76587822ee33e560ad55876d858e384158272cd9947abdd4ad42ca/wrapt-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2879af909312d0baf35f08edeea918ee3af7ab57c37fe47cb6a373c9f2749c7b", size = 120627, upload-time = "2025-11-07T00:44:14.431Z" }, + { url = "https://files.pythonhosted.org/packages/7c/7b/38df30fd629fbd7612c407643c63e80e1c60bcc982e30ceeae163a9800e7/wrapt-2.0.1-cp313-cp313-win32.whl", hash = "sha256:d67956c676be5a24102c7407a71f4126d30de2a569a1c7871c9f3cabc94225d7", size = 58252, upload-time = "2025-11-07T00:44:17.814Z" }, + { url = "https://files.pythonhosted.org/packages/85/64/d3954e836ea67c4d3ad5285e5c8fd9d362fd0a189a2db622df457b0f4f6a/wrapt-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9ca66b38dd642bf90c59b6738af8070747b610115a39af2498535f62b5cdc1c3", size = 60500, upload-time = "2025-11-07T00:44:15.561Z" }, + { url = "https://files.pythonhosted.org/packages/89/4e/3c8b99ac93527cfab7f116089db120fef16aac96e5f6cdb724ddf286086d/wrapt-2.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:5a4939eae35db6b6cec8e7aa0e833dcca0acad8231672c26c2a9ab7a0f8ac9c8", size = 58993, upload-time = "2025-11-07T00:44:16.65Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f4/eff2b7d711cae20d220780b9300faa05558660afb93f2ff5db61fe725b9a/wrapt-2.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a52f93d95c8d38fed0669da2ebdb0b0376e895d84596a976c15a9eb45e3eccb3", size = 82028, upload-time = "2025-11-07T00:44:18.944Z" }, + { url = "https://files.pythonhosted.org/packages/0c/67/cb945563f66fd0f61a999339460d950f4735c69f18f0a87ca586319b1778/wrapt-2.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e54bbf554ee29fcceee24fa41c4d091398b911da6e7f5d7bffda963c9aed2e1", size = 62949, upload-time = "2025-11-07T00:44:20.074Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ca/f63e177f0bbe1e5cf5e8d9b74a286537cd709724384ff20860f8f6065904/wrapt-2.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:908f8c6c71557f4deaa280f55d0728c3bca0960e8c3dd5ceeeafb3c19942719d", size = 63681, upload-time = "2025-11-07T00:44:21.345Z" }, + { url = "https://files.pythonhosted.org/packages/39/a1/1b88fcd21fd835dca48b556daef750952e917a2794fa20c025489e2e1f0f/wrapt-2.0.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e2f84e9af2060e3904a32cea9bb6db23ce3f91cfd90c6b426757cf7cc01c45c7", size = 152696, upload-time = "2025-11-07T00:44:24.318Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/d9185500c1960d9f5f77b9c0b890b7fc62282b53af7ad1b6bd779157f714/wrapt-2.0.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3612dc06b436968dfb9142c62e5dfa9eb5924f91120b3c8ff501ad878f90eb3", size = 158859, upload-time = "2025-11-07T00:44:25.494Z" }, + { url = "https://files.pythonhosted.org/packages/91/60/5d796ed0f481ec003220c7878a1d6894652efe089853a208ea0838c13086/wrapt-2.0.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d2d947d266d99a1477cd005b23cbd09465276e302515e122df56bb9511aca1b", size = 146068, upload-time = "2025-11-07T00:44:22.81Z" }, + { url = "https://files.pythonhosted.org/packages/04/f8/75282dd72f102ddbfba137e1e15ecba47b40acff32c08ae97edbf53f469e/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7d539241e87b650cbc4c3ac9f32c8d1ac8a54e510f6dca3f6ab60dcfd48c9b10", size = 155724, upload-time = "2025-11-07T00:44:26.634Z" }, + { url = "https://files.pythonhosted.org/packages/5a/27/fe39c51d1b344caebb4a6a9372157bdb8d25b194b3561b52c8ffc40ac7d1/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:4811e15d88ee62dbf5c77f2c3ff3932b1e3ac92323ba3912f51fc4016ce81ecf", size = 144413, upload-time = "2025-11-07T00:44:27.939Z" }, + { url = "https://files.pythonhosted.org/packages/83/2b/9f6b643fe39d4505c7bf926d7c2595b7cb4b607c8c6b500e56c6b36ac238/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c1c91405fcf1d501fa5d55df21e58ea49e6b879ae829f1039faaf7e5e509b41e", size = 150325, upload-time = "2025-11-07T00:44:29.29Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/20ffcf2558596a7f58a2e69c89597128781f0b88e124bf5a4cadc05b8139/wrapt-2.0.1-cp313-cp313t-win32.whl", hash = "sha256:e76e3f91f864e89db8b8d2a8311d57df93f01ad6bb1e9b9976d1f2e83e18315c", size = 59943, upload-time = "2025-11-07T00:44:33.211Z" }, + { url = "https://files.pythonhosted.org/packages/87/6a/0e56111cbb3320151eed5d3821ee1373be13e05b376ea0870711f18810c3/wrapt-2.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:83ce30937f0ba0d28818807b303a412440c4b63e39d3d8fc036a94764b728c92", size = 63240, upload-time = "2025-11-07T00:44:30.935Z" }, + { url = "https://files.pythonhosted.org/packages/1d/54/5ab4c53ea1f7f7e5c3e7c1095db92932cc32fd62359d285486d00c2884c3/wrapt-2.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:4b55cacc57e1dc2d0991dbe74c6419ffd415fb66474a02335cb10efd1aa3f84f", size = 60416, upload-time = "2025-11-07T00:44:32.002Z" }, + { url = "https://files.pythonhosted.org/packages/73/81/d08d83c102709258e7730d3cd25befd114c60e43ef3891d7e6877971c514/wrapt-2.0.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:5e53b428f65ece6d9dad23cb87e64506392b720a0b45076c05354d27a13351a1", size = 78290, upload-time = "2025-11-07T00:44:34.691Z" }, + { url = "https://files.pythonhosted.org/packages/f6/14/393afba2abb65677f313aa680ff0981e829626fed39b6a7e3ec807487790/wrapt-2.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ad3ee9d0f254851c71780966eb417ef8e72117155cff04821ab9b60549694a55", size = 61255, upload-time = "2025-11-07T00:44:35.762Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/a4a1f2fba205a9462e36e708ba37e5ac95f4987a0f1f8fd23f0bf1fc3b0f/wrapt-2.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d7b822c61ed04ee6ad64bc90d13368ad6eb094db54883b5dde2182f67a7f22c0", size = 61797, upload-time = "2025-11-07T00:44:37.22Z" }, + { url = "https://files.pythonhosted.org/packages/12/db/99ba5c37cf1c4fad35349174f1e38bd8d992340afc1ff27f526729b98986/wrapt-2.0.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7164a55f5e83a9a0b031d3ffab4d4e36bbec42e7025db560f225489fa929e509", size = 120470, upload-time = "2025-11-07T00:44:39.425Z" }, + { url = "https://files.pythonhosted.org/packages/30/3f/a1c8d2411eb826d695fc3395a431757331582907a0ec59afce8fe8712473/wrapt-2.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e60690ba71a57424c8d9ff28f8d006b7ad7772c22a4af432188572cd7fa004a1", size = 122851, upload-time = "2025-11-07T00:44:40.582Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8d/72c74a63f201768d6a04a8845c7976f86be6f5ff4d74996c272cefc8dafc/wrapt-2.0.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3cd1a4bd9a7a619922a8557e1318232e7269b5fb69d4ba97b04d20450a6bf970", size = 117433, upload-time = "2025-11-07T00:44:38.313Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5a/df37cf4042cb13b08256f8e27023e2f9b3d471d553376616591bb99bcb31/wrapt-2.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b4c2e3d777e38e913b8ce3a6257af72fb608f86a1df471cb1d4339755d0a807c", size = 121280, upload-time = "2025-11-07T00:44:41.69Z" }, + { url = "https://files.pythonhosted.org/packages/54/34/40d6bc89349f9931e1186ceb3e5fbd61d307fef814f09fbbac98ada6a0c8/wrapt-2.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3d366aa598d69416b5afedf1faa539fac40c1d80a42f6b236c88c73a3c8f2d41", size = 116343, upload-time = "2025-11-07T00:44:43.013Z" }, + { url = "https://files.pythonhosted.org/packages/70/66/81c3461adece09d20781dee17c2366fdf0cb8754738b521d221ca056d596/wrapt-2.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c235095d6d090aa903f1db61f892fffb779c1eaeb2a50e566b52001f7a0f66ed", size = 119650, upload-time = "2025-11-07T00:44:44.523Z" }, + { url = "https://files.pythonhosted.org/packages/46/3a/d0146db8be8761a9e388cc9cc1c312b36d583950ec91696f19bbbb44af5a/wrapt-2.0.1-cp314-cp314-win32.whl", hash = "sha256:bfb5539005259f8127ea9c885bdc231978c06b7a980e63a8a61c8c4c979719d0", size = 58701, upload-time = "2025-11-07T00:44:48.277Z" }, + { url = "https://files.pythonhosted.org/packages/1a/38/5359da9af7d64554be63e9046164bd4d8ff289a2dd365677d25ba3342c08/wrapt-2.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:4ae879acc449caa9ed43fc36ba08392b9412ee67941748d31d94e3cedb36628c", size = 60947, upload-time = "2025-11-07T00:44:46.086Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3f/96db0619276a833842bf36343685fa04f987dd6e3037f314531a1e00492b/wrapt-2.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:8639b843c9efd84675f1e100ed9e99538ebea7297b62c4b45a7042edb84db03e", size = 59359, upload-time = "2025-11-07T00:44:47.164Z" }, + { url = "https://files.pythonhosted.org/packages/71/49/5f5d1e867bf2064bf3933bc6cf36ade23505f3902390e175e392173d36a2/wrapt-2.0.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:9219a1d946a9b32bb23ccae66bdb61e35c62773ce7ca6509ceea70f344656b7b", size = 82031, upload-time = "2025-11-07T00:44:49.4Z" }, + { url = "https://files.pythonhosted.org/packages/2b/89/0009a218d88db66ceb83921e5685e820e2c61b59bbbb1324ba65342668bc/wrapt-2.0.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fa4184e74197af3adad3c889a1af95b53bb0466bced92ea99a0c014e48323eec", size = 62952, upload-time = "2025-11-07T00:44:50.74Z" }, + { url = "https://files.pythonhosted.org/packages/ae/18/9b968e920dd05d6e44bcc918a046d02afea0fb31b2f1c80ee4020f377cbe/wrapt-2.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c5ef2f2b8a53b7caee2f797ef166a390fef73979b15778a4a153e4b5fedce8fa", size = 63688, upload-time = "2025-11-07T00:44:52.248Z" }, + { url = "https://files.pythonhosted.org/packages/a6/7d/78bdcb75826725885d9ea26c49a03071b10c4c92da93edda612910f150e4/wrapt-2.0.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e042d653a4745be832d5aa190ff80ee4f02c34b21f4b785745eceacd0907b815", size = 152706, upload-time = "2025-11-07T00:44:54.613Z" }, + { url = "https://files.pythonhosted.org/packages/dd/77/cac1d46f47d32084a703df0d2d29d47e7eb2a7d19fa5cbca0e529ef57659/wrapt-2.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2afa23318136709c4b23d87d543b425c399887b4057936cd20386d5b1422b6fa", size = 158866, upload-time = "2025-11-07T00:44:55.79Z" }, + { url = "https://files.pythonhosted.org/packages/8a/11/b521406daa2421508903bf8d5e8b929216ec2af04839db31c0a2c525eee0/wrapt-2.0.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c72328f668cf4c503ffcf9434c2b71fdd624345ced7941bc6693e61bbe36bef", size = 146148, upload-time = "2025-11-07T00:44:53.388Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c0/340b272bed297baa7c9ce0c98ef7017d9c035a17a6a71dce3184b8382da2/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3793ac154afb0e5b45d1233cb94d354ef7a983708cc3bb12563853b1d8d53747", size = 155737, upload-time = "2025-11-07T00:44:56.971Z" }, + { url = "https://files.pythonhosted.org/packages/f3/93/bfcb1fb2bdf186e9c2883a4d1ab45ab099c79cbf8f4e70ea453811fa3ea7/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fec0d993ecba3991645b4857837277469c8cc4c554a7e24d064d1ca291cfb81f", size = 144451, upload-time = "2025-11-07T00:44:58.515Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6b/dca504fb18d971139d232652656180e3bd57120e1193d9a5899c3c0b7cdd/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:949520bccc1fa227274da7d03bf238be15389cd94e32e4297b92337df9b7a349", size = 150353, upload-time = "2025-11-07T00:44:59.753Z" }, + { url = "https://files.pythonhosted.org/packages/1d/f6/a1de4bd3653afdf91d250ca5c721ee51195df2b61a4603d4b373aa804d1d/wrapt-2.0.1-cp314-cp314t-win32.whl", hash = "sha256:be9e84e91d6497ba62594158d3d31ec0486c60055c49179edc51ee43d095f79c", size = 60609, upload-time = "2025-11-07T00:45:03.315Z" }, + { url = "https://files.pythonhosted.org/packages/01/3a/07cd60a9d26fe73efead61c7830af975dfdba8537632d410462672e4432b/wrapt-2.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:61c4956171c7434634401db448371277d07032a81cc21c599c22953374781395", size = 64038, upload-time = "2025-11-07T00:45:00.948Z" }, + { url = "https://files.pythonhosted.org/packages/41/99/8a06b8e17dddbf321325ae4eb12465804120f699cd1b8a355718300c62da/wrapt-2.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:35cdbd478607036fee40273be8ed54a451f5f23121bd9d4be515158f9498f7ad", size = 60634, upload-time = "2025-11-07T00:45:02.087Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, +] From a9a914840ffea9a5ff42ec5f11efb26624ec710e Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sun, 7 Dec 2025 12:06:58 +0700 Subject: [PATCH 289/305] test: integration test for user feedback (#3880) * test: integration test for user feedback * fix(test): try to set shell to True to use environment variables * chore: debug nodejs sdk output * test: run user feedback test only on feature-complete * test: make javascript file relative * Update _integration-test/nodejs/package.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update _integration-test/test_01_basics.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- _integration-test/nodejs/.gitignore | 1 + _integration-test/nodejs/instrument.js | 12 + _integration-test/nodejs/package-lock.json | 1010 ++++++++++++++++++++ _integration-test/nodejs/package.json | 13 + _integration-test/nodejs/user-feedback.js | 11 + _integration-test/test_01_basics.py | 31 + action.yaml | 11 + 7 files changed, 1089 insertions(+) create mode 100644 _integration-test/nodejs/.gitignore create mode 100644 _integration-test/nodejs/instrument.js create mode 100644 _integration-test/nodejs/package-lock.json create mode 100644 _integration-test/nodejs/package.json create mode 100644 _integration-test/nodejs/user-feedback.js diff --git a/_integration-test/nodejs/.gitignore b/_integration-test/nodejs/.gitignore new file mode 100644 index 00000000000..3c3629e647f --- /dev/null +++ b/_integration-test/nodejs/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/_integration-test/nodejs/instrument.js b/_integration-test/nodejs/instrument.js new file mode 100644 index 00000000000..b966ceb8da1 --- /dev/null +++ b/_integration-test/nodejs/instrument.js @@ -0,0 +1,12 @@ +import * as Sentry from "@sentry/node"; + +Sentry.init({ + dsn: process.env.SENTRY_DSN, + sampleRate: 1.0, + tracesSampleRate: 1.0, + enableLogs: true, + profileLifecycle: "manual", + sendClientReports: true, + sendDefaultPii: true, + debug: true, +}); diff --git a/_integration-test/nodejs/package-lock.json b/_integration-test/nodejs/package-lock.json new file mode 100644 index 00000000000..518ac91fd99 --- /dev/null +++ b/_integration-test/nodejs/package-lock.json @@ -0,0 +1,1010 @@ +{ + "name": "sentry-self-hosted-integration-test-nodejs", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sentry-self-hosted-integration-test-nodejs", + "version": "0.0.0", + "dependencies": { + "@sentry/node": "^10.5.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.203.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.203.0.tgz", + "integrity": "sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.0.1.tgz", + "integrity": "sha512-XuY23lSI3d4PEqKA+7SLtAgwqIfc6E/E9eAQWLN1vlpC53ybO3o6jW4BsXo1xvz9lYyyWItfQDDLzezER01mCw==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.203.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.203.0.tgz", + "integrity": "sha512-ke1qyM+3AK2zPuBPb6Hk/GCsc5ewbLvPNkEuELx/JmANeEp6ZjnZ+wypPAJSucTw0wvCGrUaibDSdcrGFoWxKQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.203.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.50.0.tgz", + "integrity": "sha512-kwNs/itehHG/qaQBcVrLNcvXVPW0I4FCOVtw3LHMLdYIqD7GJ6Yv2nX+a4YHjzbzIeRYj8iyMp0Bl7tlkidq5w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.47.0.tgz", + "integrity": "sha512-pjenvjR6+PMRb6/4X85L4OtkQCootgb/Jzh/l/Utu3SJHBid1F+gk9sTGU2FWuhhEfV6P7MZ7BmCdHXQjgJ42g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/connect": "3.4.38" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.21.0.tgz", + "integrity": "sha512-Xu4CZ1bfhdkV3G6iVHFgKTgHx8GbKSqrTU01kcIJRGHpowVnyOPEv1CW5ow+9GU2X4Eki8zoNuVUenFc3RluxQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.52.0.tgz", + "integrity": "sha512-W7pizN0Wh1/cbNhhTf7C62NpyYw7VfCFTYg0DYieSTrtPBT1vmoSZei19wfKLnrMsz3sHayCg0HxCVL2c+cz5w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.23.0.tgz", + "integrity": "sha512-Puan+QopWHA/KNYvDfOZN6M/JtF6buXEyD934vrb8WhsX1/FuM7OtoMlQyIqAadnE8FqqDL4KDPiEfCQH6pQcQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.47.0.tgz", + "integrity": "sha512-UfHqf3zYK+CwDwEtTjaD12uUqGGTswZ7ofLBEdQ4sEJp9GHSSJMQ2hT3pgBxyKADzUdoxQAv/7NqvL42ZI+Qbw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.51.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.51.0.tgz", + "integrity": "sha512-LchkOu9X5DrXAnPI1+Z06h/EH/zC7D6sA86hhPrk3evLlsJTz0grPrkL/yUJM9Ty0CL/y2HSvmWQCjbJEz/ADg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.50.0.tgz", + "integrity": "sha512-5xGusXOFQXKacrZmDbpHQzqYD1gIkrMWuwvlrEPkYOsjUqGUjl1HbxCsn5Y9bUXOCgP1Lj6A4PcKt1UiJ2MujA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.203.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.203.0.tgz", + "integrity": "sha512-y3uQAcCOAwnO6vEuNVocmpVzG3PER6/YZqbPbbffDdJ9te5NkHEkfSMNzlC3+v7KlE+WinPGc3N7MR30G1HY2g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/instrumentation": "0.203.0", + "@opentelemetry/semantic-conventions": "^1.29.0", + "forwarded-parse": "2.1.2" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.51.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.51.0.tgz", + "integrity": "sha512-9IUws0XWCb80NovS+17eONXsw1ZJbHwYYMXiwsfR9TSurkLV5UNbRSKb9URHO+K+pIJILy9wCxvyiOneMr91Ig==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/redis-common": "^0.38.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-kafkajs": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.12.0.tgz", + "integrity": "sha512-bIe4aSAAxytp88nzBstgr6M7ZiEpW6/D1/SuKXdxxuprf18taVvFL2H5BDNGZ7A14K27haHqzYqtCTqFXHZOYg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.30.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.48.0.tgz", + "integrity": "sha512-V5wuaBPv/lwGxuHjC6Na2JFRjtPgstw19jTFl1B1b6zvaX8zVDYUDaR5hL7glnQtUSCMktPttQsgK4dhXpddcA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.33.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.51.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.51.0.tgz", + "integrity": "sha512-XNLWeMTMG1/EkQBbgPYzCeBD0cwOrfnn8ao4hWgLv0fNCFQu1kCsJYygz2cvKuCs340RlnG4i321hX7R8gj3Rg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.48.0.tgz", + "integrity": "sha512-KUW29wfMlTPX1wFz+NNrmE7IzN7NWZDrmFWHM/VJcmFEuQGnnBuTIdsP55CnBDxKgQ/qqYFp4udQFNtjeFosPw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.56.0.tgz", + "integrity": "sha512-YG5IXUUmxX3Md2buVMvxm9NWlKADrnavI36hbJsihqqvBGsWnIfguf0rUP5Srr0pfPqhQjUP+agLMsvu0GmUpA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.50.0.tgz", + "integrity": "sha512-Am8pk1Ct951r4qCiqkBcGmPIgGhoDiFcRtqPSLbJrUZqEPUsigjtMjoWDRLG1Ki1NHgOF7D0H7d+suWz1AAizw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.49.0.tgz", + "integrity": "sha512-QU9IUNqNsrlfE3dJkZnFHqLjlndiU39ll/YAAEvWE40sGOCi9AtOF6rmEGzJ1IswoZ3oyePV7q2MP8SrhJfVAA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/mysql": "2.15.27" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.49.0.tgz", + "integrity": "sha512-dCub9wc02mkJWNyHdVEZ7dvRzy295SmNJa+LrAJY2a/+tIiVBQqEAajFzKwp9zegVVnel9L+WORu34rGLQDzxA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.41.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.55.0.tgz", + "integrity": "sha512-yfJ5bYE7CnkW/uNsnrwouG/FR7nmg09zdk2MSs7k0ZOMkDDAE3WBGpVFFApGgNu2U+gtzLgEzOQG4I/X+60hXw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.41.0", + "@types/pg": "8.15.4", + "@types/pg-pool": "2.0.6" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis": { + "version": "0.51.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.51.0.tgz", + "integrity": "sha512-uL/GtBA0u72YPPehwOvthAe+Wf8k3T+XQPBssJmTYl6fzuZjNq8zTfxVFhl9nRFjFVEe+CtiYNT0Q3AyqW1Z0A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/redis-common": "^0.38.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.22.0.tgz", + "integrity": "sha512-XrrNSUCyEjH1ax9t+Uo6lv0S2FCCykcF7hSxBMxKf7Xn0bPRxD3KyFUZy25aQXzbbbUHhtdxj3r2h88SfEM3aA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/tedious": "^4.0.14" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-undici": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.14.0.tgz", + "integrity": "sha512-2HN+7ztxAReXuxzrtA3WboAKlfP5OsPA57KQn2AdYZbJ3zeRPcLXyW4uO/jpLE6PLm0QRtmeGCmfYpqRlwgSwg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.7.0" + } + }, + "node_modules/@opentelemetry/redis-common": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.38.0.tgz", + "integrity": "sha512-4Wc0AWURII2cfXVVoZ6vDqK+s5n4K5IssdrlVrvGsx6OEOKdghKtJZqXAHWFiZv4nTDLH2/2fldjIHY8clMOjQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.36.0.tgz", + "integrity": "sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sql-common": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.41.0.tgz", + "integrity": "sha512-pmzXctVbEERbqSfiAgdes9Y63xjoOyXcD7B6IXBkVb+vbM7M9U98mn33nGXxPf4dfYR0M+vhcKRZmbSJ7HfqFA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, + "node_modules/@prisma/instrumentation": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-6.13.0.tgz", + "integrity": "sha512-b97b0sBycGh89RQcqobSgjGl3jwPaC5cQIOFod6EX1v0zIxlXPmL3ckSXxoHpy+Js0QV/tgCzFvqicMJCtezBA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.8" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/api-logs": { + "version": "0.57.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.57.2.tgz", + "integrity": "sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/instrumentation": { + "version": "0.57.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.57.2.tgz", + "integrity": "sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.57.2", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@sentry/core": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.5.0.tgz", + "integrity": "sha512-jTJ8NhZSKB2yj3QTVRXfCCngQzAOLThQUxCl9A7Mv+XF10tP7xbH/88MVQ5WiOr2IzcmrB9r2nmUe36BnMlLjA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.5.0.tgz", + "integrity": "sha512-GqTkOc7tkWqRTKNjipysElh/bzIkhfLsvNGwH6+zel5kU15IdOCFtAqIri85ZLo9vbaIVtjQELXOzfo/5MMAFQ==", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^2.0.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/instrumentation-amqplib": "0.50.0", + "@opentelemetry/instrumentation-connect": "0.47.0", + "@opentelemetry/instrumentation-dataloader": "0.21.0", + "@opentelemetry/instrumentation-express": "0.52.0", + "@opentelemetry/instrumentation-fs": "0.23.0", + "@opentelemetry/instrumentation-generic-pool": "0.47.0", + "@opentelemetry/instrumentation-graphql": "0.51.0", + "@opentelemetry/instrumentation-hapi": "0.50.0", + "@opentelemetry/instrumentation-http": "0.203.0", + "@opentelemetry/instrumentation-ioredis": "0.51.0", + "@opentelemetry/instrumentation-kafkajs": "0.12.0", + "@opentelemetry/instrumentation-knex": "0.48.0", + "@opentelemetry/instrumentation-koa": "0.51.0", + "@opentelemetry/instrumentation-lru-memoizer": "0.48.0", + "@opentelemetry/instrumentation-mongodb": "0.56.0", + "@opentelemetry/instrumentation-mongoose": "0.50.0", + "@opentelemetry/instrumentation-mysql": "0.49.0", + "@opentelemetry/instrumentation-mysql2": "0.49.0", + "@opentelemetry/instrumentation-pg": "0.55.0", + "@opentelemetry/instrumentation-redis": "0.51.0", + "@opentelemetry/instrumentation-tedious": "0.22.0", + "@opentelemetry/instrumentation-undici": "0.14.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-trace-base": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.34.0", + "@prisma/instrumentation": "6.13.0", + "@sentry/core": "10.5.0", + "@sentry/node-core": "10.5.0", + "@sentry/opentelemetry": "10.5.0", + "import-in-the-middle": "^1.14.2", + "minimatch": "^9.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node-core": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.5.0.tgz", + "integrity": "sha512-VC4FCKMvvbUT32apTE0exfI/WigqKskzQA+VdFz61Y+T7mTCADngNrOjG3ilVYPBU7R9KEEziEd/oKgencqkmQ==", + "license": "MIT", + "dependencies": { + "@sentry/core": "10.5.0", + "@sentry/opentelemetry": "10.5.0", + "import-in-the-middle": "^1.14.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", + "@opentelemetry/core": "^1.30.1 || ^2.0.0", + "@opentelemetry/instrumentation": ">=0.57.1 <1", + "@opentelemetry/resources": "^1.30.1 || ^2.0.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", + "@opentelemetry/semantic-conventions": "^1.34.0" + } + }, + "node_modules/@sentry/opentelemetry": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.5.0.tgz", + "integrity": "sha512-/Qva5vngtuh79YUUBA8kbbrD6w/A+u1vy1jnLoPMKDxWTfNPqT4tCiOOmWYotnITaE3QO0UtXK/j7LMX8FhtUA==", + "license": "MIT", + "dependencies": { + "@sentry/core": "10.5.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", + "@opentelemetry/core": "^1.30.1 || ^2.0.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", + "@opentelemetry/semantic-conventions": "^1.34.0" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mysql": { + "version": "2.15.27", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.27.tgz", + "integrity": "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", + "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/pg": { + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.4.tgz", + "integrity": "sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/pg-pool": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz", + "integrity": "sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==", + "license": "MIT", + "dependencies": { + "@types/pg": "*" + } + }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==", + "license": "MIT" + }, + "node_modules/@types/tedious": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", + "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/forwarded-parse": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", + "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", + "license": "MIT" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/import-in-the-middle": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.14.2.tgz", + "integrity": "sha512-5tCuY9BV8ujfOpwtAGgsTx9CGUapcFMEEyByLv1B+v2+6DhAcw+Zr0nhQT7uwaZ7DiourxFEscghOR8e1aPLQw==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "license": "BSD-2-Clause" + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/_integration-test/nodejs/package.json b/_integration-test/nodejs/package.json new file mode 100644 index 00000000000..032a669c294 --- /dev/null +++ b/_integration-test/nodejs/package.json @@ -0,0 +1,13 @@ +{ + "name": "sentry-self-hosted-integration-test-nodejs", + "version": "0.0.0", + "description": "Scripts to run for features only available on Nodejs SDK", + "author": "Sentry ", + "type": "module", + "scripts": { + "start": "node --import ./instrument.js index.js" + }, + "dependencies": { + "@sentry/node": "^10.5.0" + } +} diff --git a/_integration-test/nodejs/user-feedback.js b/_integration-test/nodejs/user-feedback.js new file mode 100644 index 00000000000..d42b5fafcfa --- /dev/null +++ b/_integration-test/nodejs/user-feedback.js @@ -0,0 +1,11 @@ +import * as Sentry from "@sentry/node"; + +Sentry.captureFeedback({ + message: "I love your startup!", + name: "John Doe", + email: "john@example.com", + url: "https://example.com", +}); + + +Sentry.flush(5000); diff --git a/_integration-test/test_01_basics.py b/_integration-test/test_01_basics.py index a552988baa1..5ae220d9560 100644 --- a/_integration-test/test_01_basics.py +++ b/_integration-test/test_01_basics.py @@ -4,6 +4,7 @@ import re import shutil import subprocess +import sys import time from functools import lru_cache from typing import Callable @@ -407,6 +408,36 @@ def placeholder_fn(): lambda x: len(json.loads(x)["data"]) > 0, ) +@pytest.mark.skipif(os.environ.get("COMPOSE_PROFILES") != "feature-complete", reason="Only run if feature-complete") +def test_receive_user_feedback_events(client_login): + client, _ = client_login + sentry_dsn = get_sentry_dsn(client) + + + # Execute `node --import instrument.js user-feedback.js` on the `nodejs` directory with the `SENTRY_DSN` env var set + env = os.environ.copy() + env["SENTRY_DSN"] = sentry_dsn + subprocess.run( + ["node", "--import", "./instrument.js", "./user-feedback.js"], + check=True, + shell=False, + env=env, + cwd="_integration-test/nodejs", + stdout=sys.stdout, + stderr=sys.stderr, + timeout=60, + ) + + poll_for_response( + f"{SENTRY_TEST_HOST}/api/0/organizations/sentry/issues/?query=issue.category%3Afeedback", + client, + lambda x: len(json.loads(x)) > 0, + ) + poll_for_response( + f"{SENTRY_TEST_HOST}/api/0/organizations/sentry/events/?dataset=issuePlatform&field=message&field=title&field=timestamp&project=1&statsPeriod=1h", + client, + lambda x: len(json.loads(x)["data"]) > 0, + ) @pytest.mark.skipif(os.environ.get("COMPOSE_PROFILES") != "feature-complete", reason="Only run if feature-complete") def test_receive_logs_events(client_login): diff --git a/action.yaml b/action.yaml index 82d1816fdb8..febe7c1a104 100644 --- a/action.yaml +++ b/action.yaml @@ -187,6 +187,17 @@ runs: sudo swapon --show free -h + - name: Setup Nodejs + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22.x" + + - name: Install Nodejs dependencies + shell: bash + run: | + cd ${{ github.action_path }}/_integration-test/nodejs + npm ci + - name: Integration Test shell: bash env: From 0900533b75b40964f8c73a4261805bcd508c6fe9 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Sun, 7 Dec 2025 21:45:37 +0700 Subject: [PATCH 290/305] fix: missing 'SENTRY_SYSTEM_SECRET_KEY' declaration on Docker Compose block (#4087) --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 846bf12556a..672a17f9f01 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -69,6 +69,7 @@ x-sentry-defaults: &sentry_defaults SENTRY_EVENT_RETENTION_DAYS: SENTRY_MAIL_HOST: SENTRY_MAX_EXTERNAL_SOURCEMAP_SIZE: + SENTRY_SYSTEM_SECRET_KEY: SENTRY_STATSD_ADDR: "${STATSD_ADDR:-}" volumes: - "sentry-data:/data" From d1f52408531c52e129540249736c561b1bb05a0c Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 8 Dec 2025 08:37:49 +0700 Subject: [PATCH 291/305] chore: ask installation type on problem report template (#4086) --- .github/ISSUE_TEMPLATE/problem-report.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/problem-report.yml b/.github/ISSUE_TEMPLATE/problem-report.yml index 1be5d3e4796..4f6766812e1 100644 --- a/.github/ISSUE_TEMPLATE/problem-report.yml +++ b/.github/ISSUE_TEMPLATE/problem-report.yml @@ -49,6 +49,15 @@ body: required: true validations: required: true + - type: input + id: installation_type + attributes: + label: Installation Type + placeholder: Fresh install / Upgrade from 24.8.0 to 25.5.1 + description: | + Are you filing this issue for a fresh install or an upgrade? + validations: + required: true - type: textarea id: repro attributes: From 1b20a287617c984bd5ea728c6bdc67c3ecf2c302 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Tue, 9 Dec 2025 11:09:41 +0700 Subject: [PATCH 292/305] chore: guard unit-test.sh from being invoked by users (#4085) --- unit-test.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/unit-test.sh b/unit-test.sh index 8dbc0d727bd..4102c31dd3c 100755 --- a/unit-test.sh +++ b/unit-test.sh @@ -1,5 +1,11 @@ #!/usr/bin/env bash +# The test should not be run by regular users. This should only be run in CI or by developers. +if [[ "$CI" != "true" ]]; then + echo "This script is intended to be run in CI or by developers only." + exit 1 +fi + export REPORT_SELF_HOSTED_ISSUES=0 # will be over-ridden in the relevant test FORCE_CLEAN=1 "./scripts/reset.sh" From 496a97ba074f0c792029affcaa5e9262622be1fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:11:05 +0700 Subject: [PATCH 293/305] build(deps): bump astral-sh/setup-uv from 7.1.4 to 7.1.5 (#4093) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.1.4 to 7.1.5. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/1e862dfacbd1d6d858c55d9b792c756523627244...ed21f2f24f8dd64503750218de024bcf64c7250a) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 7.1.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index febe7c1a104..82e9442761c 100644 --- a/action.yaml +++ b/action.yaml @@ -52,7 +52,7 @@ runs: df -h - name: Setup uv - uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 + uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5 with: working-directory: ${{ github.action_path }} version: "0.9.15" From 4e752506cac34b1a974d395ed0a633b972a589b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:11:15 +0700 Subject: [PATCH 294/305] build(deps): bump actions/setup-node from 4.4.0 to 6.1.0 (#4091) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.4.0 to 6.1.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/49933ea5288caeca8642d1e84afbd3f7d6820020...395ad3262231945c25e8478fd5baf05154b1d79f) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 82e9442761c..a2d3c4cb09c 100644 --- a/action.yaml +++ b/action.yaml @@ -188,7 +188,7 @@ runs: free -h - name: Setup Nodejs - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version: "22.x" From 83f07124bf9f5a821cf854f625378da20a8cebdb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:11:24 +0700 Subject: [PATCH 295/305] build(deps): bump actions/create-github-app-token from 2.2.0 to 2.2.1 (#4090) Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2.2.0 to 2.2.1. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/7e473efe3cb98aa54f8d4bac15400b15fad77d94...29824e69f54612133e76f7eaac726eef6c875baf) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 2.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3b92906be2b..b84687a22d6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} From f9c0c31f437d0f75afe62708f18b1c661b4e5a2b Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 9 Dec 2025 13:17:28 +0000 Subject: [PATCH 296/305] Revert "ref: migrate to uv (#4061)" (#4094) This reverts commit 9b4f9ea82e599e51c487178b2c829c0f5b8ad8d0 and 496a97ba074f0c792029affcaa5e9262622be1fb. --- .github/workflows/fast-revert.yml | 4 +- .github/workflows/pre-commit.yml | 6 +- .github/workflows/release.yml | 8 +- .github/workflows/shellcheck.yml | 2 +- .github/workflows/test.yml | 4 +- .gitignore | 3 + .python-version | 1 - action.yaml | 19 +- pyproject.toml | 19 - requirements-dev.txt | 8 + uv.lock | 630 ------------------------------ 11 files changed, 26 insertions(+), 678 deletions(-) delete mode 100644 .python-version delete mode 100644 pyproject.toml create mode 100644 requirements-dev.txt delete mode 100644 uv.lock diff --git a/.github/workflows/fast-revert.yml b/.github/workflows/fast-revert.yml index 8c7b7953ea4..7a52386f0ab 100644 --- a/.github/workflows/fast-revert.yml +++ b/.github/workflows/fast-revert.yml @@ -19,10 +19,10 @@ jobs: if: | github.event_name == 'workflow_dispatch' || github.event.label.name == 'Trigger: Revert' steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@v6 with: token: ${{ secrets.BUMP_SENTRY_TOKEN }} - - uses: getsentry/action-fast-revert@35b4b6c1f8f91b5911159568b3b15e531b5b8174 # v2.0.1 + - uses: getsentry/action-fast-revert@v2.0.1 with: pr: ${{ github.event.number || github.event.inputs.pr }} co_authored_by: ${{ github.event.inputs.co_authored_by || format('{0} <{1}+{0}@users.noreply.github.com>', github.event.sender.login, github.event.sender.id) }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 5d8ca4adee9..53dfb67c6e4 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -12,8 +12,8 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: 3.x - - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b84687a22d6..605a9661b4e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,13 +27,13 @@ jobs: with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@v6 with: token: ${{ steps.token.outputs.token }} fetch-depth: 0 - name: Prepare release id: prepare-release - uses: getsentry/action-prepare-release@3cea80dc3938c0baf5ec4ce752ecb311f8780cdc # v1.6.4 + uses: getsentry/action-prepare-release@v1 env: GITHUB_TOKEN: ${{ steps.token.outputs.token }} with: @@ -48,10 +48,10 @@ jobs: name: Create release on self-hosted dogfood instance needs: release steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@v6 with: fetch-depth: 0 - - uses: getsentry/action-release@128c5058bbbe93c8e02147fe0a9c713f166259a6 # v3.4.0 + - uses: getsentry/action-release@v3 env: SENTRY_ORG: self-hosted SENTRY_PROJECT: installer diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index a712b50fc43..8e991d8b9f2 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Repository checkout - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 57948e1d0ec..fed6749de15 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: name: ${{ matrix.os == 'ubuntu-24.04-arm' && 'unit tests (arm64)' || 'unit tests' }} steps: - name: Checkout - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@v6 - name: Get Compose uses: ./get-compose-action @@ -56,7 +56,7 @@ jobs: CONTAINER_ENGINE_PODMAN: ${{ matrix.container_engine == 'podman' && '1' || '0' }} steps: - name: Checkout - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + uses: actions/checkout@v6 - name: Install Podman if: matrix.container_engine == 'podman' diff --git a/.gitignore b/.gitignore index 98550a3c2bb..26d3ff590b1 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,9 @@ target/ # Ipython Notebook .ipynb_checkpoints +# pyenv +.python-version + # https://docs.docker.com/compose/extends/ docker-compose.override.yml diff --git a/.python-version b/.python-version deleted file mode 100644 index e4fba218358..00000000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12 diff --git a/action.yaml b/action.yaml index a2d3c4cb09c..2aa879b3882 100644 --- a/action.yaml +++ b/action.yaml @@ -51,24 +51,11 @@ runs: sudo rm -rf /usr/share/dotnet /usr/share/doc/dotnet-* df -h - - name: Setup uv - uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5 - with: - working-directory: ${{ github.action_path }} - version: "0.9.15" - # we just cache the venv-dir directly in action-setup-venv - enable-cache: false - - - uses: getsentry/action-setup-venv@0958463ee0e02b9e8aa8f8e031afae1f84b80881 # v3.0.0 - with: - cache-dependency-path: uv.lock - install-cmd: uv sync --frozen --active - - name: Setup dev environment shell: bash run: | cd ${{ github.action_path }} - + pip install -r requirements-dev.txt echo "PY_COLORS=1" >> "$GITHUB_ENV" ### pytest-sentry configuration ### if [ "$GITHUB_REPOSITORY" = "getsentry/self-hosted" ]; then @@ -215,7 +202,7 @@ runs: - name: Upload coverage to Codecov if: inputs.CODECOV_TOKEN continue-on-error: true - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + uses: codecov/codecov-action@v5 with: directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} @@ -224,7 +211,7 @@ runs: - name: Upload test results to Codecov if: inputs.CODECOV_TOKEN && !cancelled() continue-on-error: true - uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1 + uses: codecov/test-results-action@v1 with: directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 692d5582c57..00000000000 --- a/pyproject.toml +++ /dev/null @@ -1,19 +0,0 @@ -[project] -name = "sentry-self-hosted" -version = "0.1.0" -description = "Sentry, feature-complete and packaged up for low-volume deployments and proofs-of-concept." -readme = "README.md" -requires-python = ">=3.11" -dependencies = [] - -[dependency-groups] -dev = [ - "beautifulsoup4>=4.7.1", - "cryptography>=43.0.3", - "httpx>=0.25.2", - "pytest>=8.0.0", - "pytest-cov>=4.1.0", - "pytest-rerunfailures>=11.0", - "pytest-sentry>=0.1.11", - "sentry-sdk>=2.4.0,<3.0.0", -] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 00000000000..97d735ef800 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,8 @@ +sentry-sdk>=2.4.0,<3.0.0 +pytest>=8.0.0 +pytest-cov>=4.1.0 +pytest-rerunfailures>=11.0 +pytest-sentry>=0.1.11 +httpx>=0.25.2 +beautifulsoup4>=4.7.1 +cryptography>=43.0.3 diff --git a/uv.lock b/uv.lock deleted file mode 100644 index d7b7e9eed9d..00000000000 --- a/uv.lock +++ /dev/null @@ -1,630 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.11" - -[[package]] -name = "anyio" -version = "4.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, -] - -[[package]] -name = "beautifulsoup4" -version = "4.14.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "soupsieve" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" }, -] - -[[package]] -name = "certifi" -version = "2025.11.12" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, -] - -[[package]] -name = "cffi" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser", marker = "implementation_name != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, - { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, - { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, - { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, - { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, - { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, - { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, - { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, - { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, - { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, - { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, - { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, - { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, - { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, - { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, - { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, - { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, - { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, - { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, - { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, - { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, - { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, - { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, - { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "coverage" -version = "7.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/89/26/4a96807b193b011588099c3b5c89fbb05294e5b90e71018e065465f34eb6/coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c", size = 819341, upload-time = "2025-11-18T13:34:20.766Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/0c/0dfe7f0487477d96432e4815537263363fb6dd7289743a796e8e51eabdf2/coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f", size = 217535, upload-time = "2025-11-18T13:32:08.812Z" }, - { url = "https://files.pythonhosted.org/packages/9b/f5/f9a4a053a5bbff023d3bec259faac8f11a1e5a6479c2ccf586f910d8dac7/coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3", size = 218044, upload-time = "2025-11-18T13:32:10.329Z" }, - { url = "https://files.pythonhosted.org/packages/95/c5/84fc3697c1fa10cd8571919bf9693f693b7373278daaf3b73e328d502bc8/coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e", size = 248440, upload-time = "2025-11-18T13:32:12.536Z" }, - { url = "https://files.pythonhosted.org/packages/f4/36/2d93fbf6a04670f3874aed397d5a5371948a076e3249244a9e84fb0e02d6/coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7", size = 250361, upload-time = "2025-11-18T13:32:13.852Z" }, - { url = "https://files.pythonhosted.org/packages/5d/49/66dc65cc456a6bfc41ea3d0758c4afeaa4068a2b2931bf83be6894cf1058/coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245", size = 252472, upload-time = "2025-11-18T13:32:15.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/1f/ebb8a18dffd406db9fcd4b3ae42254aedcaf612470e8712f12041325930f/coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b", size = 248592, upload-time = "2025-11-18T13:32:16.328Z" }, - { url = "https://files.pythonhosted.org/packages/da/a8/67f213c06e5ea3b3d4980df7dc344d7fea88240b5fe878a5dcbdfe0e2315/coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64", size = 250167, upload-time = "2025-11-18T13:32:17.687Z" }, - { url = "https://files.pythonhosted.org/packages/f0/00/e52aef68154164ea40cc8389c120c314c747fe63a04b013a5782e989b77f/coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742", size = 248238, upload-time = "2025-11-18T13:32:19.2Z" }, - { url = "https://files.pythonhosted.org/packages/1f/a4/4d88750bcf9d6d66f77865e5a05a20e14db44074c25fd22519777cb69025/coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c", size = 247964, upload-time = "2025-11-18T13:32:21.027Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6b/b74693158899d5b47b0bf6238d2c6722e20ba749f86b74454fac0696bb00/coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984", size = 248862, upload-time = "2025-11-18T13:32:22.304Z" }, - { url = "https://files.pythonhosted.org/packages/18/de/6af6730227ce0e8ade307b1cc4a08e7f51b419a78d02083a86c04ccceb29/coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6", size = 220033, upload-time = "2025-11-18T13:32:23.714Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a1/e7f63021a7c4fe20994359fcdeae43cbef4a4d0ca36a5a1639feeea5d9e1/coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4", size = 220966, upload-time = "2025-11-18T13:32:25.599Z" }, - { url = "https://files.pythonhosted.org/packages/77/e8/deae26453f37c20c3aa0c4433a1e32cdc169bf415cce223a693117aa3ddd/coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc", size = 219637, upload-time = "2025-11-18T13:32:27.265Z" }, - { url = "https://files.pythonhosted.org/packages/02/bf/638c0427c0f0d47638242e2438127f3c8ee3cfc06c7fdeb16778ed47f836/coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647", size = 217704, upload-time = "2025-11-18T13:32:28.906Z" }, - { url = "https://files.pythonhosted.org/packages/08/e1/706fae6692a66c2d6b871a608bbde0da6281903fa0e9f53a39ed441da36a/coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736", size = 218064, upload-time = "2025-11-18T13:32:30.161Z" }, - { url = "https://files.pythonhosted.org/packages/a9/8b/eb0231d0540f8af3ffda39720ff43cb91926489d01524e68f60e961366e4/coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60", size = 249560, upload-time = "2025-11-18T13:32:31.835Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a1/67fb52af642e974d159b5b379e4d4c59d0ebe1288677fbd04bbffe665a82/coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8", size = 252318, upload-time = "2025-11-18T13:32:33.178Z" }, - { url = "https://files.pythonhosted.org/packages/41/e5/38228f31b2c7665ebf9bdfdddd7a184d56450755c7e43ac721c11a4b8dab/coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f", size = 253403, upload-time = "2025-11-18T13:32:34.45Z" }, - { url = "https://files.pythonhosted.org/packages/ec/4b/df78e4c8188f9960684267c5a4897836f3f0f20a20c51606ee778a1d9749/coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70", size = 249984, upload-time = "2025-11-18T13:32:35.747Z" }, - { url = "https://files.pythonhosted.org/packages/ba/51/bb163933d195a345c6f63eab9e55743413d064c291b6220df754075c2769/coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0", size = 251339, upload-time = "2025-11-18T13:32:37.352Z" }, - { url = "https://files.pythonhosted.org/packages/15/40/c9b29cdb8412c837cdcbc2cfa054547dd83affe6cbbd4ce4fdb92b6ba7d1/coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068", size = 249489, upload-time = "2025-11-18T13:32:39.212Z" }, - { url = "https://files.pythonhosted.org/packages/c8/da/b3131e20ba07a0de4437a50ef3b47840dfabf9293675b0cd5c2c7f66dd61/coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b", size = 249070, upload-time = "2025-11-18T13:32:40.598Z" }, - { url = "https://files.pythonhosted.org/packages/70/81/b653329b5f6302c08d683ceff6785bc60a34be9ae92a5c7b63ee7ee7acec/coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937", size = 250929, upload-time = "2025-11-18T13:32:42.915Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/250ac3bca9f252a5fb1338b5ad01331ebb7b40223f72bef5b1b2cb03aa64/coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa", size = 220241, upload-time = "2025-11-18T13:32:44.665Z" }, - { url = "https://files.pythonhosted.org/packages/64/1c/77e79e76d37ce83302f6c21980b45e09f8aa4551965213a10e62d71ce0ab/coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a", size = 221051, upload-time = "2025-11-18T13:32:46.008Z" }, - { url = "https://files.pythonhosted.org/packages/31/f5/641b8a25baae564f9e52cac0e2667b123de961985709a004e287ee7663cc/coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c", size = 219692, upload-time = "2025-11-18T13:32:47.372Z" }, - { url = "https://files.pythonhosted.org/packages/b8/14/771700b4048774e48d2c54ed0c674273702713c9ee7acdfede40c2666747/coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941", size = 217725, upload-time = "2025-11-18T13:32:49.22Z" }, - { url = "https://files.pythonhosted.org/packages/17/a7/3aa4144d3bcb719bf67b22d2d51c2d577bf801498c13cb08f64173e80497/coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a", size = 218098, upload-time = "2025-11-18T13:32:50.78Z" }, - { url = "https://files.pythonhosted.org/packages/fc/9c/b846bbc774ff81091a12a10203e70562c91ae71badda00c5ae5b613527b1/coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d", size = 249093, upload-time = "2025-11-18T13:32:52.554Z" }, - { url = "https://files.pythonhosted.org/packages/76/b6/67d7c0e1f400b32c883e9342de4a8c2ae7c1a0b57c5de87622b7262e2309/coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211", size = 251686, upload-time = "2025-11-18T13:32:54.862Z" }, - { url = "https://files.pythonhosted.org/packages/cc/75/b095bd4b39d49c3be4bffbb3135fea18a99a431c52dd7513637c0762fecb/coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d", size = 252930, upload-time = "2025-11-18T13:32:56.417Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f3/466f63015c7c80550bead3093aacabf5380c1220a2a93c35d374cae8f762/coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c", size = 249296, upload-time = "2025-11-18T13:32:58.074Z" }, - { url = "https://files.pythonhosted.org/packages/27/86/eba2209bf2b7e28c68698fc13437519a295b2d228ba9e0ec91673e09fa92/coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9", size = 251068, upload-time = "2025-11-18T13:32:59.646Z" }, - { url = "https://files.pythonhosted.org/packages/ec/55/ca8ae7dbba962a3351f18940b359b94c6bafdd7757945fdc79ec9e452dc7/coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0", size = 249034, upload-time = "2025-11-18T13:33:01.481Z" }, - { url = "https://files.pythonhosted.org/packages/7a/d7/39136149325cad92d420b023b5fd900dabdd1c3a0d1d5f148ef4a8cedef5/coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508", size = 248853, upload-time = "2025-11-18T13:33:02.935Z" }, - { url = "https://files.pythonhosted.org/packages/fe/b6/76e1add8b87ef60e00643b0b7f8f7bb73d4bf5249a3be19ebefc5793dd25/coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc", size = 250619, upload-time = "2025-11-18T13:33:04.336Z" }, - { url = "https://files.pythonhosted.org/packages/95/87/924c6dc64f9203f7a3c1832a6a0eee5a8335dbe5f1bdadcc278d6f1b4d74/coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8", size = 220261, upload-time = "2025-11-18T13:33:06.493Z" }, - { url = "https://files.pythonhosted.org/packages/91/77/dd4aff9af16ff776bf355a24d87eeb48fc6acde54c907cc1ea89b14a8804/coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07", size = 221072, upload-time = "2025-11-18T13:33:07.926Z" }, - { url = "https://files.pythonhosted.org/packages/70/49/5c9dc46205fef31b1b226a6e16513193715290584317fd4df91cdaf28b22/coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc", size = 219702, upload-time = "2025-11-18T13:33:09.631Z" }, - { url = "https://files.pythonhosted.org/packages/9b/62/f87922641c7198667994dd472a91e1d9b829c95d6c29529ceb52132436ad/coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87", size = 218420, upload-time = "2025-11-18T13:33:11.153Z" }, - { url = "https://files.pythonhosted.org/packages/85/dd/1cc13b2395ef15dbb27d7370a2509b4aee77890a464fb35d72d428f84871/coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6", size = 218773, upload-time = "2025-11-18T13:33:12.569Z" }, - { url = "https://files.pythonhosted.org/packages/74/40/35773cc4bb1e9d4658d4fb669eb4195b3151bef3bbd6f866aba5cd5dac82/coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7", size = 260078, upload-time = "2025-11-18T13:33:14.037Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ee/231bb1a6ffc2905e396557585ebc6bdc559e7c66708376d245a1f1d330fc/coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560", size = 262144, upload-time = "2025-11-18T13:33:15.601Z" }, - { url = "https://files.pythonhosted.org/packages/28/be/32f4aa9f3bf0b56f3971001b56508352c7753915345d45fab4296a986f01/coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12", size = 264574, upload-time = "2025-11-18T13:33:17.354Z" }, - { url = "https://files.pythonhosted.org/packages/68/7c/00489fcbc2245d13ab12189b977e0cf06ff3351cb98bc6beba8bd68c5902/coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296", size = 259298, upload-time = "2025-11-18T13:33:18.958Z" }, - { url = "https://files.pythonhosted.org/packages/96/b4/f0760d65d56c3bea95b449e02570d4abd2549dc784bf39a2d4721a2d8ceb/coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507", size = 262150, upload-time = "2025-11-18T13:33:20.644Z" }, - { url = "https://files.pythonhosted.org/packages/c5/71/9a9314df00f9326d78c1e5a910f520d599205907432d90d1c1b7a97aa4b1/coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d", size = 259763, upload-time = "2025-11-18T13:33:22.189Z" }, - { url = "https://files.pythonhosted.org/packages/10/34/01a0aceed13fbdf925876b9a15d50862eb8845454301fe3cdd1df08b2182/coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2", size = 258653, upload-time = "2025-11-18T13:33:24.239Z" }, - { url = "https://files.pythonhosted.org/packages/8d/04/81d8fd64928acf1574bbb0181f66901c6c1c6279c8ccf5f84259d2c68ae9/coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455", size = 260856, upload-time = "2025-11-18T13:33:26.365Z" }, - { url = "https://files.pythonhosted.org/packages/f2/76/fa2a37bfaeaf1f766a2d2360a25a5297d4fb567098112f6517475eee120b/coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d", size = 220936, upload-time = "2025-11-18T13:33:28.165Z" }, - { url = "https://files.pythonhosted.org/packages/f9/52/60f64d932d555102611c366afb0eb434b34266b1d9266fc2fe18ab641c47/coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c", size = 222001, upload-time = "2025-11-18T13:33:29.656Z" }, - { url = "https://files.pythonhosted.org/packages/77/df/c303164154a5a3aea7472bf323b7c857fed93b26618ed9fc5c2955566bb0/coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d", size = 220273, upload-time = "2025-11-18T13:33:31.415Z" }, - { url = "https://files.pythonhosted.org/packages/bf/2e/fc12db0883478d6e12bbd62d481210f0c8daf036102aa11434a0c5755825/coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92", size = 217777, upload-time = "2025-11-18T13:33:32.86Z" }, - { url = "https://files.pythonhosted.org/packages/1f/c1/ce3e525d223350c6ec16b9be8a057623f54226ef7f4c2fee361ebb6a02b8/coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360", size = 218100, upload-time = "2025-11-18T13:33:34.532Z" }, - { url = "https://files.pythonhosted.org/packages/15/87/113757441504aee3808cb422990ed7c8bcc2d53a6779c66c5adef0942939/coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac", size = 249151, upload-time = "2025-11-18T13:33:36.135Z" }, - { url = "https://files.pythonhosted.org/packages/d9/1d/9529d9bd44049b6b05bb319c03a3a7e4b0a8a802d28fa348ad407e10706d/coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d", size = 251667, upload-time = "2025-11-18T13:33:37.996Z" }, - { url = "https://files.pythonhosted.org/packages/11/bb/567e751c41e9c03dc29d3ce74b8c89a1e3396313e34f255a2a2e8b9ebb56/coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c", size = 253003, upload-time = "2025-11-18T13:33:39.553Z" }, - { url = "https://files.pythonhosted.org/packages/e4/b3/c2cce2d8526a02fb9e9ca14a263ca6fc074449b33a6afa4892838c903528/coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434", size = 249185, upload-time = "2025-11-18T13:33:42.086Z" }, - { url = "https://files.pythonhosted.org/packages/0e/a7/967f93bb66e82c9113c66a8d0b65ecf72fc865adfba5a145f50c7af7e58d/coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc", size = 251025, upload-time = "2025-11-18T13:33:43.634Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b2/f2f6f56337bc1af465d5b2dc1ee7ee2141b8b9272f3bf6213fcbc309a836/coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc", size = 248979, upload-time = "2025-11-18T13:33:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/f4/7a/bf4209f45a4aec09d10a01a57313a46c0e0e8f4c55ff2965467d41a92036/coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e", size = 248800, upload-time = "2025-11-18T13:33:47.546Z" }, - { url = "https://files.pythonhosted.org/packages/b8/b7/1e01b8696fb0521810f60c5bbebf699100d6754183e6cc0679bf2ed76531/coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17", size = 250460, upload-time = "2025-11-18T13:33:49.537Z" }, - { url = "https://files.pythonhosted.org/packages/71/ae/84324fb9cb46c024760e706353d9b771a81b398d117d8c1fe010391c186f/coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933", size = 220533, upload-time = "2025-11-18T13:33:51.16Z" }, - { url = "https://files.pythonhosted.org/packages/e2/71/1033629deb8460a8f97f83e6ac4ca3b93952e2b6f826056684df8275e015/coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe", size = 221348, upload-time = "2025-11-18T13:33:52.776Z" }, - { url = "https://files.pythonhosted.org/packages/0a/5f/ac8107a902f623b0c251abdb749be282dc2ab61854a8a4fcf49e276fce2f/coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d", size = 219922, upload-time = "2025-11-18T13:33:54.316Z" }, - { url = "https://files.pythonhosted.org/packages/79/6e/f27af2d4da367f16077d21ef6fe796c874408219fa6dd3f3efe7751bd910/coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d", size = 218511, upload-time = "2025-11-18T13:33:56.343Z" }, - { url = "https://files.pythonhosted.org/packages/67/dd/65fd874aa460c30da78f9d259400d8e6a4ef457d61ab052fd248f0050558/coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03", size = 218771, upload-time = "2025-11-18T13:33:57.966Z" }, - { url = "https://files.pythonhosted.org/packages/55/e0/7c6b71d327d8068cb79c05f8f45bf1b6145f7a0de23bbebe63578fe5240a/coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9", size = 260151, upload-time = "2025-11-18T13:33:59.597Z" }, - { url = "https://files.pythonhosted.org/packages/49/ce/4697457d58285b7200de6b46d606ea71066c6e674571a946a6ea908fb588/coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6", size = 262257, upload-time = "2025-11-18T13:34:01.166Z" }, - { url = "https://files.pythonhosted.org/packages/2f/33/acbc6e447aee4ceba88c15528dbe04a35fb4d67b59d393d2e0d6f1e242c1/coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339", size = 264671, upload-time = "2025-11-18T13:34:02.795Z" }, - { url = "https://files.pythonhosted.org/packages/87/ec/e2822a795c1ed44d569980097be839c5e734d4c0c1119ef8e0a073496a30/coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e", size = 259231, upload-time = "2025-11-18T13:34:04.397Z" }, - { url = "https://files.pythonhosted.org/packages/72/c5/a7ec5395bb4a49c9b7ad97e63f0c92f6bf4a9e006b1393555a02dae75f16/coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13", size = 262137, upload-time = "2025-11-18T13:34:06.068Z" }, - { url = "https://files.pythonhosted.org/packages/67/0c/02c08858b764129f4ecb8e316684272972e60777ae986f3865b10940bdd6/coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f", size = 259745, upload-time = "2025-11-18T13:34:08.04Z" }, - { url = "https://files.pythonhosted.org/packages/5a/04/4fd32b7084505f3829a8fe45c1a74a7a728cb251aaadbe3bec04abcef06d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1", size = 258570, upload-time = "2025-11-18T13:34:09.676Z" }, - { url = "https://files.pythonhosted.org/packages/48/35/2365e37c90df4f5342c4fa202223744119fe31264ee2924f09f074ea9b6d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b", size = 260899, upload-time = "2025-11-18T13:34:11.259Z" }, - { url = "https://files.pythonhosted.org/packages/05/56/26ab0464ca733fa325e8e71455c58c1c374ce30f7c04cebb88eabb037b18/coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a", size = 221313, upload-time = "2025-11-18T13:34:12.863Z" }, - { url = "https://files.pythonhosted.org/packages/da/1c/017a3e1113ed34d998b27d2c6dba08a9e7cb97d362f0ec988fcd873dcf81/coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291", size = 222423, upload-time = "2025-11-18T13:34:15.14Z" }, - { url = "https://files.pythonhosted.org/packages/4c/36/bcc504fdd5169301b52568802bb1b9cdde2e27a01d39fbb3b4b508ab7c2c/coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384", size = 220459, upload-time = "2025-11-18T13:34:17.222Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" }, -] - -[package.optional-dependencies] -toml = [ - { name = "tomli", marker = "python_full_version <= '3.11'" }, -] - -[[package]] -name = "cryptography" -version = "46.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, - { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, - { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, - { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, - { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, - { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, - { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, - { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, - { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, - { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, - { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e2/a510aa736755bffa9d2f75029c229111a1d02f8ecd5de03078f4c18d91a3/cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217", size = 7158012, upload-time = "2025-10-15T23:17:19.982Z" }, - { url = "https://files.pythonhosted.org/packages/73/dc/9aa866fbdbb95b02e7f9d086f1fccfeebf8953509b87e3f28fff927ff8a0/cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5", size = 4288728, upload-time = "2025-10-15T23:17:21.527Z" }, - { url = "https://files.pythonhosted.org/packages/c5/fd/bc1daf8230eaa075184cbbf5f8cd00ba9db4fd32d63fb83da4671b72ed8a/cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715", size = 4435078, upload-time = "2025-10-15T23:17:23.042Z" }, - { url = "https://files.pythonhosted.org/packages/82/98/d3bd5407ce4c60017f8ff9e63ffee4200ab3e23fe05b765cab805a7db008/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54", size = 4293460, upload-time = "2025-10-15T23:17:24.885Z" }, - { url = "https://files.pythonhosted.org/packages/26/e9/e23e7900983c2b8af7a08098db406cf989d7f09caea7897e347598d4cd5b/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459", size = 3995237, upload-time = "2025-10-15T23:17:26.449Z" }, - { url = "https://files.pythonhosted.org/packages/91/15/af68c509d4a138cfe299d0d7ddb14afba15233223ebd933b4bbdbc7155d3/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422", size = 4967344, upload-time = "2025-10-15T23:17:28.06Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e3/8643d077c53868b681af077edf6b3cb58288b5423610f21c62aadcbe99f4/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7", size = 4466564, upload-time = "2025-10-15T23:17:29.665Z" }, - { url = "https://files.pythonhosted.org/packages/0e/43/c1e8726fa59c236ff477ff2b5dc071e54b21e5a1e51aa2cee1676f1c986f/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044", size = 4292415, upload-time = "2025-10-15T23:17:31.686Z" }, - { url = "https://files.pythonhosted.org/packages/42/f9/2f8fefdb1aee8a8e3256a0568cffc4e6d517b256a2fe97a029b3f1b9fe7e/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665", size = 4931457, upload-time = "2025-10-15T23:17:33.478Z" }, - { url = "https://files.pythonhosted.org/packages/79/30/9b54127a9a778ccd6d27c3da7563e9f2d341826075ceab89ae3b41bf5be2/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3", size = 4466074, upload-time = "2025-10-15T23:17:35.158Z" }, - { url = "https://files.pythonhosted.org/packages/ac/68/b4f4a10928e26c941b1b6a179143af9f4d27d88fe84a6a3c53592d2e76bf/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20", size = 4420569, upload-time = "2025-10-15T23:17:37.188Z" }, - { url = "https://files.pythonhosted.org/packages/a3/49/3746dab4c0d1979888f125226357d3262a6dd40e114ac29e3d2abdf1ec55/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de", size = 4681941, upload-time = "2025-10-15T23:17:39.236Z" }, - { url = "https://files.pythonhosted.org/packages/fd/30/27654c1dbaf7e4a3531fa1fc77986d04aefa4d6d78259a62c9dc13d7ad36/cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914", size = 3022339, upload-time = "2025-10-15T23:17:40.888Z" }, - { url = "https://files.pythonhosted.org/packages/f6/30/640f34ccd4d2a1bc88367b54b926b781b5a018d65f404d409aba76a84b1c/cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db", size = 3494315, upload-time = "2025-10-15T23:17:42.769Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8b/88cc7e3bd0a8e7b861f26981f7b820e1f46aa9d26cc482d0feba0ecb4919/cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21", size = 2919331, upload-time = "2025-10-15T23:17:44.468Z" }, - { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, - { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, - { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, - { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, - { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, - { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, - { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, - { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, - { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, - { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, - { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, - { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, - { url = "https://files.pythonhosted.org/packages/06/8a/e60e46adab4362a682cf142c7dcb5bf79b782ab2199b0dcb81f55970807f/cryptography-46.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ce938a99998ed3c8aa7e7272dca1a610401ede816d36d0693907d863b10d9ea", size = 3698132, upload-time = "2025-10-15T23:18:17.056Z" }, - { url = "https://files.pythonhosted.org/packages/da/38/f59940ec4ee91e93d3311f7532671a5cef5570eb04a144bf203b58552d11/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:191bb60a7be5e6f54e30ba16fdfae78ad3a342a0599eb4193ba88e3f3d6e185b", size = 4243992, upload-time = "2025-10-15T23:18:18.695Z" }, - { url = "https://files.pythonhosted.org/packages/b0/0c/35b3d92ddebfdfda76bb485738306545817253d0a3ded0bfe80ef8e67aa5/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c70cc23f12726be8f8bc72e41d5065d77e4515efae3690326764ea1b07845cfb", size = 4409944, upload-time = "2025-10-15T23:18:20.597Z" }, - { url = "https://files.pythonhosted.org/packages/99/55/181022996c4063fc0e7666a47049a1ca705abb9c8a13830f074edb347495/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:9394673a9f4de09e28b5356e7fff97d778f8abad85c9d5ac4a4b7e25a0de7717", size = 4242957, upload-time = "2025-10-15T23:18:22.18Z" }, - { url = "https://files.pythonhosted.org/packages/ba/af/72cd6ef29f9c5f731251acadaeb821559fe25f10852f44a63374c9ca08c1/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94cd0549accc38d1494e1f8de71eca837d0509d0d44bf11d158524b0e12cebf9", size = 4409447, upload-time = "2025-10-15T23:18:24.209Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c3/e90f4a4feae6410f914f8ebac129b9ae7a8c92eb60a638012dde42030a9d/cryptography-46.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6b5063083824e5509fdba180721d55909ffacccc8adbec85268b48439423d78c", size = 3438528, upload-time = "2025-10-15T23:18:26.227Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, -] - -[[package]] -name = "packaging" -version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, -] - -[[package]] -name = "pycparser" -version = "2.23" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, -] - -[[package]] -name = "pytest" -version = "9.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, -] - -[[package]] -name = "pytest-cov" -version = "7.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "coverage", extra = ["toml"] }, - { name = "pluggy" }, - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, -] - -[[package]] -name = "pytest-rerunfailures" -version = "16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/04/71e9520551fc8fe2cf5c1a1842e4e600265b0815f2016b7c27ec85688682/pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e", size = 30889, upload-time = "2025-10-10T07:06:01.238Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/54/60eabb34445e3db3d3d874dc1dfa72751bfec3265bd611cb13c8b290adea/pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86", size = 14093, upload-time = "2025-10-10T07:06:00.019Z" }, -] - -[[package]] -name = "pytest-sentry" -version = "0.3.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pytest" }, - { name = "sentry-sdk" }, - { name = "wrapt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/44/dbe8420883c6bd89247339f521580ae9c91838bfee0159d5183161063483/pytest_sentry-0.3.3.tar.gz", hash = "sha256:c14ff1b0a00fb62fb83c9523fe03ee00896ac61829a3b20a7a57b1d4524e3336", size = 9346, upload-time = "2025-02-24T18:20:28.74Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/4f/ebacd5c58186bad0f61312771ed344448dd4e9967ef627f31b5b7ac85d92/pytest_sentry-0.3.3-py3-none-any.whl", hash = "sha256:acf2b76cf5eb3213371f5d29868dab0e35e0653012d5e87af9da82f043cdfb87", size = 8514, upload-time = "2025-02-24T18:20:27.042Z" }, -] - -[[package]] -name = "sentry-sdk" -version = "2.46.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/d7/c140a5837649e2bf2ec758494fde1d9a016c76777eab64e75ef38d685bbb/sentry_sdk-2.46.0.tar.gz", hash = "sha256:91821a23460725734b7741523021601593f35731808afc0bb2ba46c27b8acd91", size = 374761, upload-time = "2025-11-24T09:34:13.932Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/b6/ce7c502a366f4835b1f9c057753f6989a92d3c70cbadb168193f5fb7499b/sentry_sdk-2.46.0-py2.py3-none-any.whl", hash = "sha256:4eeeb60198074dff8d066ea153fa6f241fef1668c10900ea53a4200abc8da9b1", size = 406266, upload-time = "2025-11-24T09:34:12.114Z" }, -] - -[[package]] -name = "sentry-self-hosted" -version = "0.1.0" -source = { virtual = "." } - -[package.dev-dependencies] -dev = [ - { name = "beautifulsoup4" }, - { name = "cryptography" }, - { name = "httpx" }, - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "pytest-rerunfailures" }, - { name = "pytest-sentry" }, - { name = "sentry-sdk" }, -] - -[package.metadata] - -[package.metadata.requires-dev] -dev = [ - { name = "beautifulsoup4", specifier = ">=4.7.1" }, - { name = "cryptography", specifier = ">=43.0.3" }, - { name = "httpx", specifier = ">=0.25.2" }, - { name = "pytest", specifier = ">=8.0.0" }, - { name = "pytest-cov", specifier = ">=4.1.0" }, - { name = "pytest-rerunfailures", specifier = ">=11.0" }, - { name = "pytest-sentry", specifier = ">=0.1.11" }, - { name = "sentry-sdk", specifier = ">=2.4.0,<3.0.0" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "soupsieve" -version = "2.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, -] - -[[package]] -name = "tomli" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, - { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, - { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, - { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, - { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, - { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, - { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, - { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, - { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, - { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, - { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, - { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" }, - { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, - { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, - { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, - { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, - { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, - { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, - { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, - { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, - { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, - { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, - { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, - { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, - { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, - { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, - { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, - { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, - { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, - { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, - { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, -] - -[[package]] -name = "urllib3" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, -] - -[[package]] -name = "wrapt" -version = "2.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/98/60/553997acf3939079dab022e37b67b1904b5b0cc235503226898ba573b10c/wrapt-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e17283f533a0d24d6e5429a7d11f250a58d28b4ae5186f8f47853e3e70d2590", size = 77480, upload-time = "2025-11-07T00:43:30.573Z" }, - { url = "https://files.pythonhosted.org/packages/2d/50/e5b3d30895d77c52105c6d5cbf94d5b38e2a3dd4a53d22d246670da98f7c/wrapt-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85df8d92158cb8f3965aecc27cf821461bb5f40b450b03facc5d9f0d4d6ddec6", size = 60690, upload-time = "2025-11-07T00:43:31.594Z" }, - { url = "https://files.pythonhosted.org/packages/f0/40/660b2898703e5cbbb43db10cdefcc294274458c3ca4c68637c2b99371507/wrapt-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1be685ac7700c966b8610ccc63c3187a72e33cab53526a27b2a285a662cd4f7", size = 61578, upload-time = "2025-11-07T00:43:32.918Z" }, - { url = "https://files.pythonhosted.org/packages/5b/36/825b44c8a10556957bc0c1d84c7b29a40e05fcf1873b6c40aa9dbe0bd972/wrapt-2.0.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:df0b6d3b95932809c5b3fecc18fda0f1e07452d05e2662a0b35548985f256e28", size = 114115, upload-time = "2025-11-07T00:43:35.605Z" }, - { url = "https://files.pythonhosted.org/packages/83/73/0a5d14bb1599677304d3c613a55457d34c344e9b60eda8a737c2ead7619e/wrapt-2.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4da7384b0e5d4cae05c97cd6f94faaf78cc8b0f791fc63af43436d98c4ab37bb", size = 116157, upload-time = "2025-11-07T00:43:37.058Z" }, - { url = "https://files.pythonhosted.org/packages/01/22/1c158fe763dbf0a119f985d945711d288994fe5514c0646ebe0eb18b016d/wrapt-2.0.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ec65a78fbd9d6f083a15d7613b2800d5663dbb6bb96003899c834beaa68b242c", size = 112535, upload-time = "2025-11-07T00:43:34.138Z" }, - { url = "https://files.pythonhosted.org/packages/5c/28/4f16861af67d6de4eae9927799b559c20ebdd4fe432e89ea7fe6fcd9d709/wrapt-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7de3cc939be0e1174969f943f3b44e0d79b6f9a82198133a5b7fc6cc92882f16", size = 115404, upload-time = "2025-11-07T00:43:39.214Z" }, - { url = "https://files.pythonhosted.org/packages/a0/8b/7960122e625fad908f189b59c4aae2d50916eb4098b0fb2819c5a177414f/wrapt-2.0.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:fb1a5b72cbd751813adc02ef01ada0b0d05d3dcbc32976ce189a1279d80ad4a2", size = 111802, upload-time = "2025-11-07T00:43:40.476Z" }, - { url = "https://files.pythonhosted.org/packages/3e/73/7881eee5ac31132a713ab19a22c9e5f1f7365c8b1df50abba5d45b781312/wrapt-2.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3fa272ca34332581e00bf7773e993d4f632594eb2d1b0b162a9038df0fd971dd", size = 113837, upload-time = "2025-11-07T00:43:42.921Z" }, - { url = "https://files.pythonhosted.org/packages/45/00/9499a3d14e636d1f7089339f96c4409bbc7544d0889f12264efa25502ae8/wrapt-2.0.1-cp311-cp311-win32.whl", hash = "sha256:fc007fdf480c77301ab1afdbb6ab22a5deee8885f3b1ed7afcb7e5e84a0e27be", size = 58028, upload-time = "2025-11-07T00:43:47.369Z" }, - { url = "https://files.pythonhosted.org/packages/70/5d/8f3d7eea52f22638748f74b102e38fdf88cb57d08ddeb7827c476a20b01b/wrapt-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:47434236c396d04875180171ee1f3815ca1eada05e24a1ee99546320d54d1d1b", size = 60385, upload-time = "2025-11-07T00:43:44.34Z" }, - { url = "https://files.pythonhosted.org/packages/14/e2/32195e57a8209003587bbbad44d5922f13e0ced2a493bb46ca882c5b123d/wrapt-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:837e31620e06b16030b1d126ed78e9383815cbac914693f54926d816d35d8edf", size = 58893, upload-time = "2025-11-07T00:43:46.161Z" }, - { url = "https://files.pythonhosted.org/packages/cb/73/8cb252858dc8254baa0ce58ce382858e3a1cf616acebc497cb13374c95c6/wrapt-2.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1fdbb34da15450f2b1d735a0e969c24bdb8d8924892380126e2a293d9902078c", size = 78129, upload-time = "2025-11-07T00:43:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/19/42/44a0db2108526ee6e17a5ab72478061158f34b08b793df251d9fbb9a7eb4/wrapt-2.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3d32794fe940b7000f0519904e247f902f0149edbe6316c710a8562fb6738841", size = 61205, upload-time = "2025-11-07T00:43:50.402Z" }, - { url = "https://files.pythonhosted.org/packages/4d/8a/5b4b1e44b791c22046e90d9b175f9a7581a8cc7a0debbb930f81e6ae8e25/wrapt-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:386fb54d9cd903ee0012c09291336469eb7b244f7183d40dc3e86a16a4bace62", size = 61692, upload-time = "2025-11-07T00:43:51.678Z" }, - { url = "https://files.pythonhosted.org/packages/11/53/3e794346c39f462bcf1f58ac0487ff9bdad02f9b6d5ee2dc84c72e0243b2/wrapt-2.0.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7b219cb2182f230676308cdcacd428fa837987b89e4b7c5c9025088b8a6c9faf", size = 121492, upload-time = "2025-11-07T00:43:55.017Z" }, - { url = "https://files.pythonhosted.org/packages/c6/7e/10b7b0e8841e684c8ca76b462a9091c45d62e8f2de9c4b1390b690eadf16/wrapt-2.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:641e94e789b5f6b4822bb8d8ebbdfc10f4e4eae7756d648b717d980f657a9eb9", size = 123064, upload-time = "2025-11-07T00:43:56.323Z" }, - { url = "https://files.pythonhosted.org/packages/0e/d1/3c1e4321fc2f5ee7fd866b2d822aa89b84495f28676fd976c47327c5b6aa/wrapt-2.0.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe21b118b9f58859b5ebaa4b130dee18669df4bd111daad082b7beb8799ad16b", size = 117403, upload-time = "2025-11-07T00:43:53.258Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b0/d2f0a413cf201c8c2466de08414a15420a25aa83f53e647b7255cc2fab5d/wrapt-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:17fb85fa4abc26a5184d93b3efd2dcc14deb4b09edcdb3535a536ad34f0b4dba", size = 121500, upload-time = "2025-11-07T00:43:57.468Z" }, - { url = "https://files.pythonhosted.org/packages/bd/45/bddb11d28ca39970a41ed48a26d210505120f925918592283369219f83cc/wrapt-2.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b89ef9223d665ab255ae42cc282d27d69704d94be0deffc8b9d919179a609684", size = 116299, upload-time = "2025-11-07T00:43:58.877Z" }, - { url = "https://files.pythonhosted.org/packages/81/af/34ba6dd570ef7a534e7eec0c25e2615c355602c52aba59413411c025a0cb/wrapt-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a453257f19c31b31ba593c30d997d6e5be39e3b5ad9148c2af5a7314061c63eb", size = 120622, upload-time = "2025-11-07T00:43:59.962Z" }, - { url = "https://files.pythonhosted.org/packages/e2/3e/693a13b4146646fb03254636f8bafd20c621955d27d65b15de07ab886187/wrapt-2.0.1-cp312-cp312-win32.whl", hash = "sha256:3e271346f01e9c8b1130a6a3b0e11908049fe5be2d365a5f402778049147e7e9", size = 58246, upload-time = "2025-11-07T00:44:03.169Z" }, - { url = "https://files.pythonhosted.org/packages/a7/36/715ec5076f925a6be95f37917b66ebbeaa1372d1862c2ccd7a751574b068/wrapt-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:2da620b31a90cdefa9cd0c2b661882329e2e19d1d7b9b920189956b76c564d75", size = 60492, upload-time = "2025-11-07T00:44:01.027Z" }, - { url = "https://files.pythonhosted.org/packages/ef/3e/62451cd7d80f65cc125f2b426b25fbb6c514bf6f7011a0c3904fc8c8df90/wrapt-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:aea9c7224c302bc8bfc892b908537f56c430802560e827b75ecbde81b604598b", size = 58987, upload-time = "2025-11-07T00:44:02.095Z" }, - { url = "https://files.pythonhosted.org/packages/ad/fe/41af4c46b5e498c90fc87981ab2972fbd9f0bccda597adb99d3d3441b94b/wrapt-2.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:47b0f8bafe90f7736151f61482c583c86b0693d80f075a58701dd1549b0010a9", size = 78132, upload-time = "2025-11-07T00:44:04.628Z" }, - { url = "https://files.pythonhosted.org/packages/1c/92/d68895a984a5ebbbfb175512b0c0aad872354a4a2484fbd5552e9f275316/wrapt-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cbeb0971e13b4bd81d34169ed57a6dda017328d1a22b62fda45e1d21dd06148f", size = 61211, upload-time = "2025-11-07T00:44:05.626Z" }, - { url = "https://files.pythonhosted.org/packages/e8/26/ba83dc5ae7cf5aa2b02364a3d9cf74374b86169906a1f3ade9a2d03cf21c/wrapt-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb7cffe572ad0a141a7886a1d2efa5bef0bf7fe021deeea76b3ab334d2c38218", size = 61689, upload-time = "2025-11-07T00:44:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/cf/67/d7a7c276d874e5d26738c22444d466a3a64ed541f6ef35f740dbd865bab4/wrapt-2.0.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8d60527d1ecfc131426b10d93ab5d53e08a09c5fa0175f6b21b3252080c70a9", size = 121502, upload-time = "2025-11-07T00:44:09.557Z" }, - { url = "https://files.pythonhosted.org/packages/0f/6b/806dbf6dd9579556aab22fc92908a876636e250f063f71548a8660382184/wrapt-2.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c654eafb01afac55246053d67a4b9a984a3567c3808bb7df2f8de1c1caba2e1c", size = 123110, upload-time = "2025-11-07T00:44:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/e5/08/cdbb965fbe4c02c5233d185d070cabed2ecc1f1e47662854f95d77613f57/wrapt-2.0.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:98d873ed6c8b4ee2418f7afce666751854d6d03e3c0ec2a399bb039cd2ae89db", size = 117434, upload-time = "2025-11-07T00:44:08.138Z" }, - { url = "https://files.pythonhosted.org/packages/2d/d1/6aae2ce39db4cb5216302fa2e9577ad74424dfbe315bd6669725569e048c/wrapt-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9e850f5b7fc67af856ff054c71690d54fa940c3ef74209ad9f935b4f66a0233", size = 121533, upload-time = "2025-11-07T00:44:12.142Z" }, - { url = "https://files.pythonhosted.org/packages/79/35/565abf57559fbe0a9155c29879ff43ce8bd28d2ca61033a3a3dd67b70794/wrapt-2.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e505629359cb5f751e16e30cf3f91a1d3ddb4552480c205947da415d597f7ac2", size = 116324, upload-time = "2025-11-07T00:44:13.28Z" }, - { url = "https://files.pythonhosted.org/packages/e1/e0/53ff5e76587822ee33e560ad55876d858e384158272cd9947abdd4ad42ca/wrapt-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2879af909312d0baf35f08edeea918ee3af7ab57c37fe47cb6a373c9f2749c7b", size = 120627, upload-time = "2025-11-07T00:44:14.431Z" }, - { url = "https://files.pythonhosted.org/packages/7c/7b/38df30fd629fbd7612c407643c63e80e1c60bcc982e30ceeae163a9800e7/wrapt-2.0.1-cp313-cp313-win32.whl", hash = "sha256:d67956c676be5a24102c7407a71f4126d30de2a569a1c7871c9f3cabc94225d7", size = 58252, upload-time = "2025-11-07T00:44:17.814Z" }, - { url = "https://files.pythonhosted.org/packages/85/64/d3954e836ea67c4d3ad5285e5c8fd9d362fd0a189a2db622df457b0f4f6a/wrapt-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9ca66b38dd642bf90c59b6738af8070747b610115a39af2498535f62b5cdc1c3", size = 60500, upload-time = "2025-11-07T00:44:15.561Z" }, - { url = "https://files.pythonhosted.org/packages/89/4e/3c8b99ac93527cfab7f116089db120fef16aac96e5f6cdb724ddf286086d/wrapt-2.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:5a4939eae35db6b6cec8e7aa0e833dcca0acad8231672c26c2a9ab7a0f8ac9c8", size = 58993, upload-time = "2025-11-07T00:44:16.65Z" }, - { url = "https://files.pythonhosted.org/packages/f9/f4/eff2b7d711cae20d220780b9300faa05558660afb93f2ff5db61fe725b9a/wrapt-2.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a52f93d95c8d38fed0669da2ebdb0b0376e895d84596a976c15a9eb45e3eccb3", size = 82028, upload-time = "2025-11-07T00:44:18.944Z" }, - { url = "https://files.pythonhosted.org/packages/0c/67/cb945563f66fd0f61a999339460d950f4735c69f18f0a87ca586319b1778/wrapt-2.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e54bbf554ee29fcceee24fa41c4d091398b911da6e7f5d7bffda963c9aed2e1", size = 62949, upload-time = "2025-11-07T00:44:20.074Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ca/f63e177f0bbe1e5cf5e8d9b74a286537cd709724384ff20860f8f6065904/wrapt-2.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:908f8c6c71557f4deaa280f55d0728c3bca0960e8c3dd5ceeeafb3c19942719d", size = 63681, upload-time = "2025-11-07T00:44:21.345Z" }, - { url = "https://files.pythonhosted.org/packages/39/a1/1b88fcd21fd835dca48b556daef750952e917a2794fa20c025489e2e1f0f/wrapt-2.0.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e2f84e9af2060e3904a32cea9bb6db23ce3f91cfd90c6b426757cf7cc01c45c7", size = 152696, upload-time = "2025-11-07T00:44:24.318Z" }, - { url = "https://files.pythonhosted.org/packages/62/1c/d9185500c1960d9f5f77b9c0b890b7fc62282b53af7ad1b6bd779157f714/wrapt-2.0.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3612dc06b436968dfb9142c62e5dfa9eb5924f91120b3c8ff501ad878f90eb3", size = 158859, upload-time = "2025-11-07T00:44:25.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/60/5d796ed0f481ec003220c7878a1d6894652efe089853a208ea0838c13086/wrapt-2.0.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d2d947d266d99a1477cd005b23cbd09465276e302515e122df56bb9511aca1b", size = 146068, upload-time = "2025-11-07T00:44:22.81Z" }, - { url = "https://files.pythonhosted.org/packages/04/f8/75282dd72f102ddbfba137e1e15ecba47b40acff32c08ae97edbf53f469e/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7d539241e87b650cbc4c3ac9f32c8d1ac8a54e510f6dca3f6ab60dcfd48c9b10", size = 155724, upload-time = "2025-11-07T00:44:26.634Z" }, - { url = "https://files.pythonhosted.org/packages/5a/27/fe39c51d1b344caebb4a6a9372157bdb8d25b194b3561b52c8ffc40ac7d1/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:4811e15d88ee62dbf5c77f2c3ff3932b1e3ac92323ba3912f51fc4016ce81ecf", size = 144413, upload-time = "2025-11-07T00:44:27.939Z" }, - { url = "https://files.pythonhosted.org/packages/83/2b/9f6b643fe39d4505c7bf926d7c2595b7cb4b607c8c6b500e56c6b36ac238/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c1c91405fcf1d501fa5d55df21e58ea49e6b879ae829f1039faaf7e5e509b41e", size = 150325, upload-time = "2025-11-07T00:44:29.29Z" }, - { url = "https://files.pythonhosted.org/packages/bb/b6/20ffcf2558596a7f58a2e69c89597128781f0b88e124bf5a4cadc05b8139/wrapt-2.0.1-cp313-cp313t-win32.whl", hash = "sha256:e76e3f91f864e89db8b8d2a8311d57df93f01ad6bb1e9b9976d1f2e83e18315c", size = 59943, upload-time = "2025-11-07T00:44:33.211Z" }, - { url = "https://files.pythonhosted.org/packages/87/6a/0e56111cbb3320151eed5d3821ee1373be13e05b376ea0870711f18810c3/wrapt-2.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:83ce30937f0ba0d28818807b303a412440c4b63e39d3d8fc036a94764b728c92", size = 63240, upload-time = "2025-11-07T00:44:30.935Z" }, - { url = "https://files.pythonhosted.org/packages/1d/54/5ab4c53ea1f7f7e5c3e7c1095db92932cc32fd62359d285486d00c2884c3/wrapt-2.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:4b55cacc57e1dc2d0991dbe74c6419ffd415fb66474a02335cb10efd1aa3f84f", size = 60416, upload-time = "2025-11-07T00:44:32.002Z" }, - { url = "https://files.pythonhosted.org/packages/73/81/d08d83c102709258e7730d3cd25befd114c60e43ef3891d7e6877971c514/wrapt-2.0.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:5e53b428f65ece6d9dad23cb87e64506392b720a0b45076c05354d27a13351a1", size = 78290, upload-time = "2025-11-07T00:44:34.691Z" }, - { url = "https://files.pythonhosted.org/packages/f6/14/393afba2abb65677f313aa680ff0981e829626fed39b6a7e3ec807487790/wrapt-2.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ad3ee9d0f254851c71780966eb417ef8e72117155cff04821ab9b60549694a55", size = 61255, upload-time = "2025-11-07T00:44:35.762Z" }, - { url = "https://files.pythonhosted.org/packages/c4/10/a4a1f2fba205a9462e36e708ba37e5ac95f4987a0f1f8fd23f0bf1fc3b0f/wrapt-2.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d7b822c61ed04ee6ad64bc90d13368ad6eb094db54883b5dde2182f67a7f22c0", size = 61797, upload-time = "2025-11-07T00:44:37.22Z" }, - { url = "https://files.pythonhosted.org/packages/12/db/99ba5c37cf1c4fad35349174f1e38bd8d992340afc1ff27f526729b98986/wrapt-2.0.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7164a55f5e83a9a0b031d3ffab4d4e36bbec42e7025db560f225489fa929e509", size = 120470, upload-time = "2025-11-07T00:44:39.425Z" }, - { url = "https://files.pythonhosted.org/packages/30/3f/a1c8d2411eb826d695fc3395a431757331582907a0ec59afce8fe8712473/wrapt-2.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e60690ba71a57424c8d9ff28f8d006b7ad7772c22a4af432188572cd7fa004a1", size = 122851, upload-time = "2025-11-07T00:44:40.582Z" }, - { url = "https://files.pythonhosted.org/packages/b3/8d/72c74a63f201768d6a04a8845c7976f86be6f5ff4d74996c272cefc8dafc/wrapt-2.0.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3cd1a4bd9a7a619922a8557e1318232e7269b5fb69d4ba97b04d20450a6bf970", size = 117433, upload-time = "2025-11-07T00:44:38.313Z" }, - { url = "https://files.pythonhosted.org/packages/c7/5a/df37cf4042cb13b08256f8e27023e2f9b3d471d553376616591bb99bcb31/wrapt-2.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b4c2e3d777e38e913b8ce3a6257af72fb608f86a1df471cb1d4339755d0a807c", size = 121280, upload-time = "2025-11-07T00:44:41.69Z" }, - { url = "https://files.pythonhosted.org/packages/54/34/40d6bc89349f9931e1186ceb3e5fbd61d307fef814f09fbbac98ada6a0c8/wrapt-2.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3d366aa598d69416b5afedf1faa539fac40c1d80a42f6b236c88c73a3c8f2d41", size = 116343, upload-time = "2025-11-07T00:44:43.013Z" }, - { url = "https://files.pythonhosted.org/packages/70/66/81c3461adece09d20781dee17c2366fdf0cb8754738b521d221ca056d596/wrapt-2.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c235095d6d090aa903f1db61f892fffb779c1eaeb2a50e566b52001f7a0f66ed", size = 119650, upload-time = "2025-11-07T00:44:44.523Z" }, - { url = "https://files.pythonhosted.org/packages/46/3a/d0146db8be8761a9e388cc9cc1c312b36d583950ec91696f19bbbb44af5a/wrapt-2.0.1-cp314-cp314-win32.whl", hash = "sha256:bfb5539005259f8127ea9c885bdc231978c06b7a980e63a8a61c8c4c979719d0", size = 58701, upload-time = "2025-11-07T00:44:48.277Z" }, - { url = "https://files.pythonhosted.org/packages/1a/38/5359da9af7d64554be63e9046164bd4d8ff289a2dd365677d25ba3342c08/wrapt-2.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:4ae879acc449caa9ed43fc36ba08392b9412ee67941748d31d94e3cedb36628c", size = 60947, upload-time = "2025-11-07T00:44:46.086Z" }, - { url = "https://files.pythonhosted.org/packages/aa/3f/96db0619276a833842bf36343685fa04f987dd6e3037f314531a1e00492b/wrapt-2.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:8639b843c9efd84675f1e100ed9e99538ebea7297b62c4b45a7042edb84db03e", size = 59359, upload-time = "2025-11-07T00:44:47.164Z" }, - { url = "https://files.pythonhosted.org/packages/71/49/5f5d1e867bf2064bf3933bc6cf36ade23505f3902390e175e392173d36a2/wrapt-2.0.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:9219a1d946a9b32bb23ccae66bdb61e35c62773ce7ca6509ceea70f344656b7b", size = 82031, upload-time = "2025-11-07T00:44:49.4Z" }, - { url = "https://files.pythonhosted.org/packages/2b/89/0009a218d88db66ceb83921e5685e820e2c61b59bbbb1324ba65342668bc/wrapt-2.0.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fa4184e74197af3adad3c889a1af95b53bb0466bced92ea99a0c014e48323eec", size = 62952, upload-time = "2025-11-07T00:44:50.74Z" }, - { url = "https://files.pythonhosted.org/packages/ae/18/9b968e920dd05d6e44bcc918a046d02afea0fb31b2f1c80ee4020f377cbe/wrapt-2.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c5ef2f2b8a53b7caee2f797ef166a390fef73979b15778a4a153e4b5fedce8fa", size = 63688, upload-time = "2025-11-07T00:44:52.248Z" }, - { url = "https://files.pythonhosted.org/packages/a6/7d/78bdcb75826725885d9ea26c49a03071b10c4c92da93edda612910f150e4/wrapt-2.0.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e042d653a4745be832d5aa190ff80ee4f02c34b21f4b785745eceacd0907b815", size = 152706, upload-time = "2025-11-07T00:44:54.613Z" }, - { url = "https://files.pythonhosted.org/packages/dd/77/cac1d46f47d32084a703df0d2d29d47e7eb2a7d19fa5cbca0e529ef57659/wrapt-2.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2afa23318136709c4b23d87d543b425c399887b4057936cd20386d5b1422b6fa", size = 158866, upload-time = "2025-11-07T00:44:55.79Z" }, - { url = "https://files.pythonhosted.org/packages/8a/11/b521406daa2421508903bf8d5e8b929216ec2af04839db31c0a2c525eee0/wrapt-2.0.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c72328f668cf4c503ffcf9434c2b71fdd624345ced7941bc6693e61bbe36bef", size = 146148, upload-time = "2025-11-07T00:44:53.388Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c0/340b272bed297baa7c9ce0c98ef7017d9c035a17a6a71dce3184b8382da2/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3793ac154afb0e5b45d1233cb94d354ef7a983708cc3bb12563853b1d8d53747", size = 155737, upload-time = "2025-11-07T00:44:56.971Z" }, - { url = "https://files.pythonhosted.org/packages/f3/93/bfcb1fb2bdf186e9c2883a4d1ab45ab099c79cbf8f4e70ea453811fa3ea7/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fec0d993ecba3991645b4857837277469c8cc4c554a7e24d064d1ca291cfb81f", size = 144451, upload-time = "2025-11-07T00:44:58.515Z" }, - { url = "https://files.pythonhosted.org/packages/d2/6b/dca504fb18d971139d232652656180e3bd57120e1193d9a5899c3c0b7cdd/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:949520bccc1fa227274da7d03bf238be15389cd94e32e4297b92337df9b7a349", size = 150353, upload-time = "2025-11-07T00:44:59.753Z" }, - { url = "https://files.pythonhosted.org/packages/1d/f6/a1de4bd3653afdf91d250ca5c721ee51195df2b61a4603d4b373aa804d1d/wrapt-2.0.1-cp314-cp314t-win32.whl", hash = "sha256:be9e84e91d6497ba62594158d3d31ec0486c60055c49179edc51ee43d095f79c", size = 60609, upload-time = "2025-11-07T00:45:03.315Z" }, - { url = "https://files.pythonhosted.org/packages/01/3a/07cd60a9d26fe73efead61c7830af975dfdba8537632d410462672e4432b/wrapt-2.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:61c4956171c7434634401db448371277d07032a81cc21c599c22953374781395", size = 64038, upload-time = "2025-11-07T00:45:00.948Z" }, - { url = "https://files.pythonhosted.org/packages/41/99/8a06b8e17dddbf321325ae4eb12465804120f699cd1b8a355718300c62da/wrapt-2.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:35cdbd478607036fee40273be8ed54a451f5f23121bd9d4be515158f9498f7ad", size = 60634, upload-time = "2025-11-07T00:45:02.087Z" }, - { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, -] From ce32fe9fc406f4c1b1e3319d747c5dbec9ddef3e Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Tue, 9 Dec 2025 22:39:38 +0000 Subject: [PATCH 297/305] fix: Provide useful info on permission errors (#4096) Prevents the very confusing 'Unsupported Docker Architecture' error when we actually had a permission error running docker. --- install/detect-platform.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/install/detect-platform.sh b/install/detect-platform.sh index 9009f79b63d..1a75835e3cb 100644 --- a/install/detect-platform.sh +++ b/install/detect-platform.sh @@ -19,7 +19,22 @@ if [[ $CONTAINER_ENGINE == "podman" ]]; then FORMAT="{{.Host.Arch}}" fi -export DOCKER_ARCH=$($CONTAINER_ENGINE info --format "$FORMAT") +DOCKER_ARCH_OUTPUT=$($CONTAINER_ENGINE info --format "$FORMAT" 2>&1) +DOCKER_INFO_EXIT_CODE=$? + +if [[ $DOCKER_INFO_EXIT_CODE -ne 0 ]]; then + echo "FAIL: Unable to get $CONTAINER_ENGINE architecture information." + echo "$DOCKER_ARCH_OUTPUT" + if [[ "$DOCKER_ARCH_OUTPUT" == *"permission denied"* ]]; then + echo "" + echo "You may need to add your user to the docker group:" + echo " sudo usermod -aG docker \$USER" + echo "Then log out and log back in, or run: newgrp docker" + fi + exit 1 +fi + +export DOCKER_ARCH="$DOCKER_ARCH_OUTPUT" if [[ "$DOCKER_ARCH" = "x86_64" || "$DOCKER_ARCH" = "amd64" ]]; then export DOCKER_PLATFORM="linux/amd64" elif [[ "$DOCKER_ARCH" = "aarch64" ]]; then From 2d66a99f231bd63f544dd8229100177a7e8ce8c9 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Thu, 11 Dec 2025 07:08:27 +0700 Subject: [PATCH 298/305] Revert "Revert "ref: migrate to uv (#4061)"" (#4097) * Revert "Revert "ref: migrate to uv (#4061)" (#4094)" This reverts commit f9c0c31f437d0f75afe62708f18b1c661b4e5a2b. * fix: provide python version as per https://github.com/getsentry/action-setup-venv/blob/0958463ee0e02b9e8aa8f8e031afae1f84b80881/action.yml#L5-L7 --- .github/workflows/fast-revert.yml | 4 +- .github/workflows/pre-commit.yml | 6 +- .github/workflows/release.yml | 8 +- .github/workflows/shellcheck.yml | 2 +- .github/workflows/test.yml | 4 +- .gitignore | 3 - .python-version | 1 + action.yaml | 20 +- pyproject.toml | 19 + requirements-dev.txt | 8 - uv.lock | 630 ++++++++++++++++++++++++++++++ 11 files changed, 679 insertions(+), 26 deletions(-) create mode 100644 .python-version create mode 100644 pyproject.toml delete mode 100644 requirements-dev.txt create mode 100644 uv.lock diff --git a/.github/workflows/fast-revert.yml b/.github/workflows/fast-revert.yml index 7a52386f0ab..8c7b7953ea4 100644 --- a/.github/workflows/fast-revert.yml +++ b/.github/workflows/fast-revert.yml @@ -19,10 +19,10 @@ jobs: if: | github.event_name == 'workflow_dispatch' || github.event.label.name == 'Trigger: Revert' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: token: ${{ secrets.BUMP_SENTRY_TOKEN }} - - uses: getsentry/action-fast-revert@v2.0.1 + - uses: getsentry/action-fast-revert@35b4b6c1f8f91b5911159568b3b15e531b5b8174 # v2.0.1 with: pr: ${{ github.event.number || github.event.inputs.pr }} co_authored_by: ${{ github.event.inputs.co_authored_by || format('{0} <{1}+{0}@users.noreply.github.com>', github.event.sender.login, github.event.sender.id) }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 53dfb67c6e4..5d8ca4adee9 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -12,8 +12,8 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: 3.x - - uses: pre-commit/action@v3.0.1 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 605a9661b4e..b84687a22d6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,13 +27,13 @@ jobs: with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} - - uses: actions/checkout@v6 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: token: ${{ steps.token.outputs.token }} fetch-depth: 0 - name: Prepare release id: prepare-release - uses: getsentry/action-prepare-release@v1 + uses: getsentry/action-prepare-release@3cea80dc3938c0baf5ec4ce752ecb311f8780cdc # v1.6.4 env: GITHUB_TOKEN: ${{ steps.token.outputs.token }} with: @@ -48,10 +48,10 @@ jobs: name: Create release on self-hosted dogfood instance needs: release steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - - uses: getsentry/action-release@v3 + - uses: getsentry/action-release@128c5058bbbe93c8e02147fe0a9c713f166259a6 # v3.4.0 env: SENTRY_ORG: self-hosted SENTRY_PROJECT: installer diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 8e991d8b9f2..a712b50fc43 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Repository checkout - uses: actions/checkout@v6 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fed6749de15..57948e1d0ec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: name: ${{ matrix.os == 'ubuntu-24.04-arm' && 'unit tests (arm64)' || 'unit tests' }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Get Compose uses: ./get-compose-action @@ -56,7 +56,7 @@ jobs: CONTAINER_ENGINE_PODMAN: ${{ matrix.container_engine == 'podman' && '1' || '0' }} steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install Podman if: matrix.container_engine == 'podman' diff --git a/.gitignore b/.gitignore index 26d3ff590b1..98550a3c2bb 100644 --- a/.gitignore +++ b/.gitignore @@ -69,9 +69,6 @@ target/ # Ipython Notebook .ipynb_checkpoints -# pyenv -.python-version - # https://docs.docker.com/compose/extends/ docker-compose.override.yml diff --git a/.python-version b/.python-version new file mode 100644 index 00000000000..e4fba218358 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/action.yaml b/action.yaml index 2aa879b3882..9df10e82920 100644 --- a/action.yaml +++ b/action.yaml @@ -51,11 +51,25 @@ runs: sudo rm -rf /usr/share/dotnet /usr/share/doc/dotnet-* df -h + - name: Setup uv + uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5 + with: + working-directory: ${{ github.action_path }} + version: "0.9.15" + # we just cache the venv-dir directly in action-setup-venv + enable-cache: false + + - uses: getsentry/action-setup-venv@0958463ee0e02b9e8aa8f8e031afae1f84b80881 # v3.0.0 + with: + python-version: "3.12" + cache-dependency-path: uv.lock + install-cmd: uv sync --frozen --active + - name: Setup dev environment shell: bash run: | cd ${{ github.action_path }} - pip install -r requirements-dev.txt + echo "PY_COLORS=1" >> "$GITHUB_ENV" ### pytest-sentry configuration ### if [ "$GITHUB_REPOSITORY" = "getsentry/self-hosted" ]; then @@ -202,7 +216,7 @@ runs: - name: Upload coverage to Codecov if: inputs.CODECOV_TOKEN continue-on-error: true - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 with: directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} @@ -211,7 +225,7 @@ runs: - name: Upload test results to Codecov if: inputs.CODECOV_TOKEN && !cancelled() continue-on-error: true - uses: codecov/test-results-action@v1 + uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1 with: directory: ${{ github.action_path }} token: ${{ inputs.CODECOV_TOKEN }} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000000..692d5582c57 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "sentry-self-hosted" +version = "0.1.0" +description = "Sentry, feature-complete and packaged up for low-volume deployments and proofs-of-concept." +readme = "README.md" +requires-python = ">=3.11" +dependencies = [] + +[dependency-groups] +dev = [ + "beautifulsoup4>=4.7.1", + "cryptography>=43.0.3", + "httpx>=0.25.2", + "pytest>=8.0.0", + "pytest-cov>=4.1.0", + "pytest-rerunfailures>=11.0", + "pytest-sentry>=0.1.11", + "sentry-sdk>=2.4.0,<3.0.0", +] diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 97d735ef800..00000000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,8 +0,0 @@ -sentry-sdk>=2.4.0,<3.0.0 -pytest>=8.0.0 -pytest-cov>=4.1.0 -pytest-rerunfailures>=11.0 -pytest-sentry>=0.1.11 -httpx>=0.25.2 -beautifulsoup4>=4.7.1 -cryptography>=43.0.3 diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000000..d7b7e9eed9d --- /dev/null +++ b/uv.lock @@ -0,0 +1,630 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/e9/df2358efd7659577435e2177bfa69cba6c33216681af51a707193dec162a/beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e", size = 625822, upload-time = "2025-09-29T10:05:42.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/fe/3aed5d0be4d404d12d36ab97e2f1791424d9ca39c2f754a6285d59a3b01d/beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515", size = 106392, upload-time = "2025-09-29T10:05:43.771Z" }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/26/4a96807b193b011588099c3b5c89fbb05294e5b90e71018e065465f34eb6/coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c", size = 819341, upload-time = "2025-11-18T13:34:20.766Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/0c/0dfe7f0487477d96432e4815537263363fb6dd7289743a796e8e51eabdf2/coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f", size = 217535, upload-time = "2025-11-18T13:32:08.812Z" }, + { url = "https://files.pythonhosted.org/packages/9b/f5/f9a4a053a5bbff023d3bec259faac8f11a1e5a6479c2ccf586f910d8dac7/coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3", size = 218044, upload-time = "2025-11-18T13:32:10.329Z" }, + { url = "https://files.pythonhosted.org/packages/95/c5/84fc3697c1fa10cd8571919bf9693f693b7373278daaf3b73e328d502bc8/coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e", size = 248440, upload-time = "2025-11-18T13:32:12.536Z" }, + { url = "https://files.pythonhosted.org/packages/f4/36/2d93fbf6a04670f3874aed397d5a5371948a076e3249244a9e84fb0e02d6/coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7", size = 250361, upload-time = "2025-11-18T13:32:13.852Z" }, + { url = "https://files.pythonhosted.org/packages/5d/49/66dc65cc456a6bfc41ea3d0758c4afeaa4068a2b2931bf83be6894cf1058/coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245", size = 252472, upload-time = "2025-11-18T13:32:15.068Z" }, + { url = "https://files.pythonhosted.org/packages/35/1f/ebb8a18dffd406db9fcd4b3ae42254aedcaf612470e8712f12041325930f/coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b", size = 248592, upload-time = "2025-11-18T13:32:16.328Z" }, + { url = "https://files.pythonhosted.org/packages/da/a8/67f213c06e5ea3b3d4980df7dc344d7fea88240b5fe878a5dcbdfe0e2315/coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64", size = 250167, upload-time = "2025-11-18T13:32:17.687Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/e52aef68154164ea40cc8389c120c314c747fe63a04b013a5782e989b77f/coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742", size = 248238, upload-time = "2025-11-18T13:32:19.2Z" }, + { url = "https://files.pythonhosted.org/packages/1f/a4/4d88750bcf9d6d66f77865e5a05a20e14db44074c25fd22519777cb69025/coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c", size = 247964, upload-time = "2025-11-18T13:32:21.027Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6b/b74693158899d5b47b0bf6238d2c6722e20ba749f86b74454fac0696bb00/coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984", size = 248862, upload-time = "2025-11-18T13:32:22.304Z" }, + { url = "https://files.pythonhosted.org/packages/18/de/6af6730227ce0e8ade307b1cc4a08e7f51b419a78d02083a86c04ccceb29/coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6", size = 220033, upload-time = "2025-11-18T13:32:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/e7f63021a7c4fe20994359fcdeae43cbef4a4d0ca36a5a1639feeea5d9e1/coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4", size = 220966, upload-time = "2025-11-18T13:32:25.599Z" }, + { url = "https://files.pythonhosted.org/packages/77/e8/deae26453f37c20c3aa0c4433a1e32cdc169bf415cce223a693117aa3ddd/coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc", size = 219637, upload-time = "2025-11-18T13:32:27.265Z" }, + { url = "https://files.pythonhosted.org/packages/02/bf/638c0427c0f0d47638242e2438127f3c8ee3cfc06c7fdeb16778ed47f836/coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647", size = 217704, upload-time = "2025-11-18T13:32:28.906Z" }, + { url = "https://files.pythonhosted.org/packages/08/e1/706fae6692a66c2d6b871a608bbde0da6281903fa0e9f53a39ed441da36a/coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736", size = 218064, upload-time = "2025-11-18T13:32:30.161Z" }, + { url = "https://files.pythonhosted.org/packages/a9/8b/eb0231d0540f8af3ffda39720ff43cb91926489d01524e68f60e961366e4/coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60", size = 249560, upload-time = "2025-11-18T13:32:31.835Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a1/67fb52af642e974d159b5b379e4d4c59d0ebe1288677fbd04bbffe665a82/coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8", size = 252318, upload-time = "2025-11-18T13:32:33.178Z" }, + { url = "https://files.pythonhosted.org/packages/41/e5/38228f31b2c7665ebf9bdfdddd7a184d56450755c7e43ac721c11a4b8dab/coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f", size = 253403, upload-time = "2025-11-18T13:32:34.45Z" }, + { url = "https://files.pythonhosted.org/packages/ec/4b/df78e4c8188f9960684267c5a4897836f3f0f20a20c51606ee778a1d9749/coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70", size = 249984, upload-time = "2025-11-18T13:32:35.747Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/bb163933d195a345c6f63eab9e55743413d064c291b6220df754075c2769/coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0", size = 251339, upload-time = "2025-11-18T13:32:37.352Z" }, + { url = "https://files.pythonhosted.org/packages/15/40/c9b29cdb8412c837cdcbc2cfa054547dd83affe6cbbd4ce4fdb92b6ba7d1/coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068", size = 249489, upload-time = "2025-11-18T13:32:39.212Z" }, + { url = "https://files.pythonhosted.org/packages/c8/da/b3131e20ba07a0de4437a50ef3b47840dfabf9293675b0cd5c2c7f66dd61/coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b", size = 249070, upload-time = "2025-11-18T13:32:40.598Z" }, + { url = "https://files.pythonhosted.org/packages/70/81/b653329b5f6302c08d683ceff6785bc60a34be9ae92a5c7b63ee7ee7acec/coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937", size = 250929, upload-time = "2025-11-18T13:32:42.915Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/250ac3bca9f252a5fb1338b5ad01331ebb7b40223f72bef5b1b2cb03aa64/coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa", size = 220241, upload-time = "2025-11-18T13:32:44.665Z" }, + { url = "https://files.pythonhosted.org/packages/64/1c/77e79e76d37ce83302f6c21980b45e09f8aa4551965213a10e62d71ce0ab/coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a", size = 221051, upload-time = "2025-11-18T13:32:46.008Z" }, + { url = "https://files.pythonhosted.org/packages/31/f5/641b8a25baae564f9e52cac0e2667b123de961985709a004e287ee7663cc/coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c", size = 219692, upload-time = "2025-11-18T13:32:47.372Z" }, + { url = "https://files.pythonhosted.org/packages/b8/14/771700b4048774e48d2c54ed0c674273702713c9ee7acdfede40c2666747/coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941", size = 217725, upload-time = "2025-11-18T13:32:49.22Z" }, + { url = "https://files.pythonhosted.org/packages/17/a7/3aa4144d3bcb719bf67b22d2d51c2d577bf801498c13cb08f64173e80497/coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a", size = 218098, upload-time = "2025-11-18T13:32:50.78Z" }, + { url = "https://files.pythonhosted.org/packages/fc/9c/b846bbc774ff81091a12a10203e70562c91ae71badda00c5ae5b613527b1/coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d", size = 249093, upload-time = "2025-11-18T13:32:52.554Z" }, + { url = "https://files.pythonhosted.org/packages/76/b6/67d7c0e1f400b32c883e9342de4a8c2ae7c1a0b57c5de87622b7262e2309/coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211", size = 251686, upload-time = "2025-11-18T13:32:54.862Z" }, + { url = "https://files.pythonhosted.org/packages/cc/75/b095bd4b39d49c3be4bffbb3135fea18a99a431c52dd7513637c0762fecb/coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d", size = 252930, upload-time = "2025-11-18T13:32:56.417Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f3/466f63015c7c80550bead3093aacabf5380c1220a2a93c35d374cae8f762/coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c", size = 249296, upload-time = "2025-11-18T13:32:58.074Z" }, + { url = "https://files.pythonhosted.org/packages/27/86/eba2209bf2b7e28c68698fc13437519a295b2d228ba9e0ec91673e09fa92/coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9", size = 251068, upload-time = "2025-11-18T13:32:59.646Z" }, + { url = "https://files.pythonhosted.org/packages/ec/55/ca8ae7dbba962a3351f18940b359b94c6bafdd7757945fdc79ec9e452dc7/coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0", size = 249034, upload-time = "2025-11-18T13:33:01.481Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d7/39136149325cad92d420b023b5fd900dabdd1c3a0d1d5f148ef4a8cedef5/coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508", size = 248853, upload-time = "2025-11-18T13:33:02.935Z" }, + { url = "https://files.pythonhosted.org/packages/fe/b6/76e1add8b87ef60e00643b0b7f8f7bb73d4bf5249a3be19ebefc5793dd25/coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc", size = 250619, upload-time = "2025-11-18T13:33:04.336Z" }, + { url = "https://files.pythonhosted.org/packages/95/87/924c6dc64f9203f7a3c1832a6a0eee5a8335dbe5f1bdadcc278d6f1b4d74/coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8", size = 220261, upload-time = "2025-11-18T13:33:06.493Z" }, + { url = "https://files.pythonhosted.org/packages/91/77/dd4aff9af16ff776bf355a24d87eeb48fc6acde54c907cc1ea89b14a8804/coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07", size = 221072, upload-time = "2025-11-18T13:33:07.926Z" }, + { url = "https://files.pythonhosted.org/packages/70/49/5c9dc46205fef31b1b226a6e16513193715290584317fd4df91cdaf28b22/coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc", size = 219702, upload-time = "2025-11-18T13:33:09.631Z" }, + { url = "https://files.pythonhosted.org/packages/9b/62/f87922641c7198667994dd472a91e1d9b829c95d6c29529ceb52132436ad/coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87", size = 218420, upload-time = "2025-11-18T13:33:11.153Z" }, + { url = "https://files.pythonhosted.org/packages/85/dd/1cc13b2395ef15dbb27d7370a2509b4aee77890a464fb35d72d428f84871/coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6", size = 218773, upload-time = "2025-11-18T13:33:12.569Z" }, + { url = "https://files.pythonhosted.org/packages/74/40/35773cc4bb1e9d4658d4fb669eb4195b3151bef3bbd6f866aba5cd5dac82/coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7", size = 260078, upload-time = "2025-11-18T13:33:14.037Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ee/231bb1a6ffc2905e396557585ebc6bdc559e7c66708376d245a1f1d330fc/coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560", size = 262144, upload-time = "2025-11-18T13:33:15.601Z" }, + { url = "https://files.pythonhosted.org/packages/28/be/32f4aa9f3bf0b56f3971001b56508352c7753915345d45fab4296a986f01/coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12", size = 264574, upload-time = "2025-11-18T13:33:17.354Z" }, + { url = "https://files.pythonhosted.org/packages/68/7c/00489fcbc2245d13ab12189b977e0cf06ff3351cb98bc6beba8bd68c5902/coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296", size = 259298, upload-time = "2025-11-18T13:33:18.958Z" }, + { url = "https://files.pythonhosted.org/packages/96/b4/f0760d65d56c3bea95b449e02570d4abd2549dc784bf39a2d4721a2d8ceb/coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507", size = 262150, upload-time = "2025-11-18T13:33:20.644Z" }, + { url = "https://files.pythonhosted.org/packages/c5/71/9a9314df00f9326d78c1e5a910f520d599205907432d90d1c1b7a97aa4b1/coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d", size = 259763, upload-time = "2025-11-18T13:33:22.189Z" }, + { url = "https://files.pythonhosted.org/packages/10/34/01a0aceed13fbdf925876b9a15d50862eb8845454301fe3cdd1df08b2182/coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2", size = 258653, upload-time = "2025-11-18T13:33:24.239Z" }, + { url = "https://files.pythonhosted.org/packages/8d/04/81d8fd64928acf1574bbb0181f66901c6c1c6279c8ccf5f84259d2c68ae9/coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455", size = 260856, upload-time = "2025-11-18T13:33:26.365Z" }, + { url = "https://files.pythonhosted.org/packages/f2/76/fa2a37bfaeaf1f766a2d2360a25a5297d4fb567098112f6517475eee120b/coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d", size = 220936, upload-time = "2025-11-18T13:33:28.165Z" }, + { url = "https://files.pythonhosted.org/packages/f9/52/60f64d932d555102611c366afb0eb434b34266b1d9266fc2fe18ab641c47/coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c", size = 222001, upload-time = "2025-11-18T13:33:29.656Z" }, + { url = "https://files.pythonhosted.org/packages/77/df/c303164154a5a3aea7472bf323b7c857fed93b26618ed9fc5c2955566bb0/coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d", size = 220273, upload-time = "2025-11-18T13:33:31.415Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2e/fc12db0883478d6e12bbd62d481210f0c8daf036102aa11434a0c5755825/coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92", size = 217777, upload-time = "2025-11-18T13:33:32.86Z" }, + { url = "https://files.pythonhosted.org/packages/1f/c1/ce3e525d223350c6ec16b9be8a057623f54226ef7f4c2fee361ebb6a02b8/coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360", size = 218100, upload-time = "2025-11-18T13:33:34.532Z" }, + { url = "https://files.pythonhosted.org/packages/15/87/113757441504aee3808cb422990ed7c8bcc2d53a6779c66c5adef0942939/coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac", size = 249151, upload-time = "2025-11-18T13:33:36.135Z" }, + { url = "https://files.pythonhosted.org/packages/d9/1d/9529d9bd44049b6b05bb319c03a3a7e4b0a8a802d28fa348ad407e10706d/coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d", size = 251667, upload-time = "2025-11-18T13:33:37.996Z" }, + { url = "https://files.pythonhosted.org/packages/11/bb/567e751c41e9c03dc29d3ce74b8c89a1e3396313e34f255a2a2e8b9ebb56/coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c", size = 253003, upload-time = "2025-11-18T13:33:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/e4/b3/c2cce2d8526a02fb9e9ca14a263ca6fc074449b33a6afa4892838c903528/coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434", size = 249185, upload-time = "2025-11-18T13:33:42.086Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a7/967f93bb66e82c9113c66a8d0b65ecf72fc865adfba5a145f50c7af7e58d/coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc", size = 251025, upload-time = "2025-11-18T13:33:43.634Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/f2f6f56337bc1af465d5b2dc1ee7ee2141b8b9272f3bf6213fcbc309a836/coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc", size = 248979, upload-time = "2025-11-18T13:33:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7a/bf4209f45a4aec09d10a01a57313a46c0e0e8f4c55ff2965467d41a92036/coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e", size = 248800, upload-time = "2025-11-18T13:33:47.546Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b7/1e01b8696fb0521810f60c5bbebf699100d6754183e6cc0679bf2ed76531/coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17", size = 250460, upload-time = "2025-11-18T13:33:49.537Z" }, + { url = "https://files.pythonhosted.org/packages/71/ae/84324fb9cb46c024760e706353d9b771a81b398d117d8c1fe010391c186f/coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933", size = 220533, upload-time = "2025-11-18T13:33:51.16Z" }, + { url = "https://files.pythonhosted.org/packages/e2/71/1033629deb8460a8f97f83e6ac4ca3b93952e2b6f826056684df8275e015/coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe", size = 221348, upload-time = "2025-11-18T13:33:52.776Z" }, + { url = "https://files.pythonhosted.org/packages/0a/5f/ac8107a902f623b0c251abdb749be282dc2ab61854a8a4fcf49e276fce2f/coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d", size = 219922, upload-time = "2025-11-18T13:33:54.316Z" }, + { url = "https://files.pythonhosted.org/packages/79/6e/f27af2d4da367f16077d21ef6fe796c874408219fa6dd3f3efe7751bd910/coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d", size = 218511, upload-time = "2025-11-18T13:33:56.343Z" }, + { url = "https://files.pythonhosted.org/packages/67/dd/65fd874aa460c30da78f9d259400d8e6a4ef457d61ab052fd248f0050558/coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03", size = 218771, upload-time = "2025-11-18T13:33:57.966Z" }, + { url = "https://files.pythonhosted.org/packages/55/e0/7c6b71d327d8068cb79c05f8f45bf1b6145f7a0de23bbebe63578fe5240a/coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9", size = 260151, upload-time = "2025-11-18T13:33:59.597Z" }, + { url = "https://files.pythonhosted.org/packages/49/ce/4697457d58285b7200de6b46d606ea71066c6e674571a946a6ea908fb588/coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6", size = 262257, upload-time = "2025-11-18T13:34:01.166Z" }, + { url = "https://files.pythonhosted.org/packages/2f/33/acbc6e447aee4ceba88c15528dbe04a35fb4d67b59d393d2e0d6f1e242c1/coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339", size = 264671, upload-time = "2025-11-18T13:34:02.795Z" }, + { url = "https://files.pythonhosted.org/packages/87/ec/e2822a795c1ed44d569980097be839c5e734d4c0c1119ef8e0a073496a30/coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e", size = 259231, upload-time = "2025-11-18T13:34:04.397Z" }, + { url = "https://files.pythonhosted.org/packages/72/c5/a7ec5395bb4a49c9b7ad97e63f0c92f6bf4a9e006b1393555a02dae75f16/coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13", size = 262137, upload-time = "2025-11-18T13:34:06.068Z" }, + { url = "https://files.pythonhosted.org/packages/67/0c/02c08858b764129f4ecb8e316684272972e60777ae986f3865b10940bdd6/coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f", size = 259745, upload-time = "2025-11-18T13:34:08.04Z" }, + { url = "https://files.pythonhosted.org/packages/5a/04/4fd32b7084505f3829a8fe45c1a74a7a728cb251aaadbe3bec04abcef06d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1", size = 258570, upload-time = "2025-11-18T13:34:09.676Z" }, + { url = "https://files.pythonhosted.org/packages/48/35/2365e37c90df4f5342c4fa202223744119fe31264ee2924f09f074ea9b6d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b", size = 260899, upload-time = "2025-11-18T13:34:11.259Z" }, + { url = "https://files.pythonhosted.org/packages/05/56/26ab0464ca733fa325e8e71455c58c1c374ce30f7c04cebb88eabb037b18/coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a", size = 221313, upload-time = "2025-11-18T13:34:12.863Z" }, + { url = "https://files.pythonhosted.org/packages/da/1c/017a3e1113ed34d998b27d2c6dba08a9e7cb97d362f0ec988fcd873dcf81/coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291", size = 222423, upload-time = "2025-11-18T13:34:15.14Z" }, + { url = "https://files.pythonhosted.org/packages/4c/36/bcc504fdd5169301b52568802bb1b9cdde2e27a01d39fbb3b4b508ab7c2c/coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384", size = 220459, upload-time = "2025-11-18T13:34:17.222Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "cryptography" +version = "46.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, + { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, + { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, + { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, + { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, + { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, + { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, + { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, + { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, + { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e2/a510aa736755bffa9d2f75029c229111a1d02f8ecd5de03078f4c18d91a3/cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217", size = 7158012, upload-time = "2025-10-15T23:17:19.982Z" }, + { url = "https://files.pythonhosted.org/packages/73/dc/9aa866fbdbb95b02e7f9d086f1fccfeebf8953509b87e3f28fff927ff8a0/cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5", size = 4288728, upload-time = "2025-10-15T23:17:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/c5/fd/bc1daf8230eaa075184cbbf5f8cd00ba9db4fd32d63fb83da4671b72ed8a/cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715", size = 4435078, upload-time = "2025-10-15T23:17:23.042Z" }, + { url = "https://files.pythonhosted.org/packages/82/98/d3bd5407ce4c60017f8ff9e63ffee4200ab3e23fe05b765cab805a7db008/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54", size = 4293460, upload-time = "2025-10-15T23:17:24.885Z" }, + { url = "https://files.pythonhosted.org/packages/26/e9/e23e7900983c2b8af7a08098db406cf989d7f09caea7897e347598d4cd5b/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459", size = 3995237, upload-time = "2025-10-15T23:17:26.449Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/af68c509d4a138cfe299d0d7ddb14afba15233223ebd933b4bbdbc7155d3/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422", size = 4967344, upload-time = "2025-10-15T23:17:28.06Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e3/8643d077c53868b681af077edf6b3cb58288b5423610f21c62aadcbe99f4/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7", size = 4466564, upload-time = "2025-10-15T23:17:29.665Z" }, + { url = "https://files.pythonhosted.org/packages/0e/43/c1e8726fa59c236ff477ff2b5dc071e54b21e5a1e51aa2cee1676f1c986f/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044", size = 4292415, upload-time = "2025-10-15T23:17:31.686Z" }, + { url = "https://files.pythonhosted.org/packages/42/f9/2f8fefdb1aee8a8e3256a0568cffc4e6d517b256a2fe97a029b3f1b9fe7e/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665", size = 4931457, upload-time = "2025-10-15T23:17:33.478Z" }, + { url = "https://files.pythonhosted.org/packages/79/30/9b54127a9a778ccd6d27c3da7563e9f2d341826075ceab89ae3b41bf5be2/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3", size = 4466074, upload-time = "2025-10-15T23:17:35.158Z" }, + { url = "https://files.pythonhosted.org/packages/ac/68/b4f4a10928e26c941b1b6a179143af9f4d27d88fe84a6a3c53592d2e76bf/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20", size = 4420569, upload-time = "2025-10-15T23:17:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/a3/49/3746dab4c0d1979888f125226357d3262a6dd40e114ac29e3d2abdf1ec55/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de", size = 4681941, upload-time = "2025-10-15T23:17:39.236Z" }, + { url = "https://files.pythonhosted.org/packages/fd/30/27654c1dbaf7e4a3531fa1fc77986d04aefa4d6d78259a62c9dc13d7ad36/cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914", size = 3022339, upload-time = "2025-10-15T23:17:40.888Z" }, + { url = "https://files.pythonhosted.org/packages/f6/30/640f34ccd4d2a1bc88367b54b926b781b5a018d65f404d409aba76a84b1c/cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db", size = 3494315, upload-time = "2025-10-15T23:17:42.769Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8b/88cc7e3bd0a8e7b861f26981f7b820e1f46aa9d26cc482d0feba0ecb4919/cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21", size = 2919331, upload-time = "2025-10-15T23:17:44.468Z" }, + { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, + { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, + { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, + { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, + { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, + { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, + { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, + { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, + { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, + { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, + { url = "https://files.pythonhosted.org/packages/06/8a/e60e46adab4362a682cf142c7dcb5bf79b782ab2199b0dcb81f55970807f/cryptography-46.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ce938a99998ed3c8aa7e7272dca1a610401ede816d36d0693907d863b10d9ea", size = 3698132, upload-time = "2025-10-15T23:18:17.056Z" }, + { url = "https://files.pythonhosted.org/packages/da/38/f59940ec4ee91e93d3311f7532671a5cef5570eb04a144bf203b58552d11/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:191bb60a7be5e6f54e30ba16fdfae78ad3a342a0599eb4193ba88e3f3d6e185b", size = 4243992, upload-time = "2025-10-15T23:18:18.695Z" }, + { url = "https://files.pythonhosted.org/packages/b0/0c/35b3d92ddebfdfda76bb485738306545817253d0a3ded0bfe80ef8e67aa5/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c70cc23f12726be8f8bc72e41d5065d77e4515efae3690326764ea1b07845cfb", size = 4409944, upload-time = "2025-10-15T23:18:20.597Z" }, + { url = "https://files.pythonhosted.org/packages/99/55/181022996c4063fc0e7666a47049a1ca705abb9c8a13830f074edb347495/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:9394673a9f4de09e28b5356e7fff97d778f8abad85c9d5ac4a4b7e25a0de7717", size = 4242957, upload-time = "2025-10-15T23:18:22.18Z" }, + { url = "https://files.pythonhosted.org/packages/ba/af/72cd6ef29f9c5f731251acadaeb821559fe25f10852f44a63374c9ca08c1/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94cd0549accc38d1494e1f8de71eca837d0509d0d44bf11d158524b0e12cebf9", size = 4409447, upload-time = "2025-10-15T23:18:24.209Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c3/e90f4a4feae6410f914f8ebac129b9ae7a8c92eb60a638012dde42030a9d/cryptography-46.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6b5063083824e5509fdba180721d55909ffacccc8adbec85268b48439423d78c", size = 3438528, upload-time = "2025-10-15T23:18:26.227Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-rerunfailures" +version = "16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/04/71e9520551fc8fe2cf5c1a1842e4e600265b0815f2016b7c27ec85688682/pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e", size = 30889, upload-time = "2025-10-10T07:06:01.238Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/54/60eabb34445e3db3d3d874dc1dfa72751bfec3265bd611cb13c8b290adea/pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86", size = 14093, upload-time = "2025-10-10T07:06:00.019Z" }, +] + +[[package]] +name = "pytest-sentry" +version = "0.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "sentry-sdk" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/44/dbe8420883c6bd89247339f521580ae9c91838bfee0159d5183161063483/pytest_sentry-0.3.3.tar.gz", hash = "sha256:c14ff1b0a00fb62fb83c9523fe03ee00896ac61829a3b20a7a57b1d4524e3336", size = 9346, upload-time = "2025-02-24T18:20:28.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/4f/ebacd5c58186bad0f61312771ed344448dd4e9967ef627f31b5b7ac85d92/pytest_sentry-0.3.3-py3-none-any.whl", hash = "sha256:acf2b76cf5eb3213371f5d29868dab0e35e0653012d5e87af9da82f043cdfb87", size = 8514, upload-time = "2025-02-24T18:20:27.042Z" }, +] + +[[package]] +name = "sentry-sdk" +version = "2.46.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/d7/c140a5837649e2bf2ec758494fde1d9a016c76777eab64e75ef38d685bbb/sentry_sdk-2.46.0.tar.gz", hash = "sha256:91821a23460725734b7741523021601593f35731808afc0bb2ba46c27b8acd91", size = 374761, upload-time = "2025-11-24T09:34:13.932Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/b6/ce7c502a366f4835b1f9c057753f6989a92d3c70cbadb168193f5fb7499b/sentry_sdk-2.46.0-py2.py3-none-any.whl", hash = "sha256:4eeeb60198074dff8d066ea153fa6f241fef1668c10900ea53a4200abc8da9b1", size = 406266, upload-time = "2025-11-24T09:34:12.114Z" }, +] + +[[package]] +name = "sentry-self-hosted" +version = "0.1.0" +source = { virtual = "." } + +[package.dev-dependencies] +dev = [ + { name = "beautifulsoup4" }, + { name = "cryptography" }, + { name = "httpx" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-rerunfailures" }, + { name = "pytest-sentry" }, + { name = "sentry-sdk" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +dev = [ + { name = "beautifulsoup4", specifier = ">=4.7.1" }, + { name = "cryptography", specifier = ">=43.0.3" }, + { name = "httpx", specifier = ">=0.25.2" }, + { name = "pytest", specifier = ">=8.0.0" }, + { name = "pytest-cov", specifier = ">=4.1.0" }, + { name = "pytest-rerunfailures", specifier = ">=11.0" }, + { name = "pytest-sentry", specifier = ">=0.1.11" }, + { name = "sentry-sdk", specifier = ">=2.4.0,<3.0.0" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472, upload-time = "2025-08-27T15:39:51.78Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679, upload-time = "2025-08-27T15:39:50.179Z" }, +] + +[[package]] +name = "tomli" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, + { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, + { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, + { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, + { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, + { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, + { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, + { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, + { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, + { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, + { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, + { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, + { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" }, + { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" }, + { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, + { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, + { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, + { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, + { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, + { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, + { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, + { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, + { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, + { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, + { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, + { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, + { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, + { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, + { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, + { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, + { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, + { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, + { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, + { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "wrapt" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/60/553997acf3939079dab022e37b67b1904b5b0cc235503226898ba573b10c/wrapt-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e17283f533a0d24d6e5429a7d11f250a58d28b4ae5186f8f47853e3e70d2590", size = 77480, upload-time = "2025-11-07T00:43:30.573Z" }, + { url = "https://files.pythonhosted.org/packages/2d/50/e5b3d30895d77c52105c6d5cbf94d5b38e2a3dd4a53d22d246670da98f7c/wrapt-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85df8d92158cb8f3965aecc27cf821461bb5f40b450b03facc5d9f0d4d6ddec6", size = 60690, upload-time = "2025-11-07T00:43:31.594Z" }, + { url = "https://files.pythonhosted.org/packages/f0/40/660b2898703e5cbbb43db10cdefcc294274458c3ca4c68637c2b99371507/wrapt-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1be685ac7700c966b8610ccc63c3187a72e33cab53526a27b2a285a662cd4f7", size = 61578, upload-time = "2025-11-07T00:43:32.918Z" }, + { url = "https://files.pythonhosted.org/packages/5b/36/825b44c8a10556957bc0c1d84c7b29a40e05fcf1873b6c40aa9dbe0bd972/wrapt-2.0.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:df0b6d3b95932809c5b3fecc18fda0f1e07452d05e2662a0b35548985f256e28", size = 114115, upload-time = "2025-11-07T00:43:35.605Z" }, + { url = "https://files.pythonhosted.org/packages/83/73/0a5d14bb1599677304d3c613a55457d34c344e9b60eda8a737c2ead7619e/wrapt-2.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4da7384b0e5d4cae05c97cd6f94faaf78cc8b0f791fc63af43436d98c4ab37bb", size = 116157, upload-time = "2025-11-07T00:43:37.058Z" }, + { url = "https://files.pythonhosted.org/packages/01/22/1c158fe763dbf0a119f985d945711d288994fe5514c0646ebe0eb18b016d/wrapt-2.0.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ec65a78fbd9d6f083a15d7613b2800d5663dbb6bb96003899c834beaa68b242c", size = 112535, upload-time = "2025-11-07T00:43:34.138Z" }, + { url = "https://files.pythonhosted.org/packages/5c/28/4f16861af67d6de4eae9927799b559c20ebdd4fe432e89ea7fe6fcd9d709/wrapt-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7de3cc939be0e1174969f943f3b44e0d79b6f9a82198133a5b7fc6cc92882f16", size = 115404, upload-time = "2025-11-07T00:43:39.214Z" }, + { url = "https://files.pythonhosted.org/packages/a0/8b/7960122e625fad908f189b59c4aae2d50916eb4098b0fb2819c5a177414f/wrapt-2.0.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:fb1a5b72cbd751813adc02ef01ada0b0d05d3dcbc32976ce189a1279d80ad4a2", size = 111802, upload-time = "2025-11-07T00:43:40.476Z" }, + { url = "https://files.pythonhosted.org/packages/3e/73/7881eee5ac31132a713ab19a22c9e5f1f7365c8b1df50abba5d45b781312/wrapt-2.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3fa272ca34332581e00bf7773e993d4f632594eb2d1b0b162a9038df0fd971dd", size = 113837, upload-time = "2025-11-07T00:43:42.921Z" }, + { url = "https://files.pythonhosted.org/packages/45/00/9499a3d14e636d1f7089339f96c4409bbc7544d0889f12264efa25502ae8/wrapt-2.0.1-cp311-cp311-win32.whl", hash = "sha256:fc007fdf480c77301ab1afdbb6ab22a5deee8885f3b1ed7afcb7e5e84a0e27be", size = 58028, upload-time = "2025-11-07T00:43:47.369Z" }, + { url = "https://files.pythonhosted.org/packages/70/5d/8f3d7eea52f22638748f74b102e38fdf88cb57d08ddeb7827c476a20b01b/wrapt-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:47434236c396d04875180171ee1f3815ca1eada05e24a1ee99546320d54d1d1b", size = 60385, upload-time = "2025-11-07T00:43:44.34Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/32195e57a8209003587bbbad44d5922f13e0ced2a493bb46ca882c5b123d/wrapt-2.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:837e31620e06b16030b1d126ed78e9383815cbac914693f54926d816d35d8edf", size = 58893, upload-time = "2025-11-07T00:43:46.161Z" }, + { url = "https://files.pythonhosted.org/packages/cb/73/8cb252858dc8254baa0ce58ce382858e3a1cf616acebc497cb13374c95c6/wrapt-2.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1fdbb34da15450f2b1d735a0e969c24bdb8d8924892380126e2a293d9902078c", size = 78129, upload-time = "2025-11-07T00:43:48.852Z" }, + { url = "https://files.pythonhosted.org/packages/19/42/44a0db2108526ee6e17a5ab72478061158f34b08b793df251d9fbb9a7eb4/wrapt-2.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3d32794fe940b7000f0519904e247f902f0149edbe6316c710a8562fb6738841", size = 61205, upload-time = "2025-11-07T00:43:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/4d/8a/5b4b1e44b791c22046e90d9b175f9a7581a8cc7a0debbb930f81e6ae8e25/wrapt-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:386fb54d9cd903ee0012c09291336469eb7b244f7183d40dc3e86a16a4bace62", size = 61692, upload-time = "2025-11-07T00:43:51.678Z" }, + { url = "https://files.pythonhosted.org/packages/11/53/3e794346c39f462bcf1f58ac0487ff9bdad02f9b6d5ee2dc84c72e0243b2/wrapt-2.0.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7b219cb2182f230676308cdcacd428fa837987b89e4b7c5c9025088b8a6c9faf", size = 121492, upload-time = "2025-11-07T00:43:55.017Z" }, + { url = "https://files.pythonhosted.org/packages/c6/7e/10b7b0e8841e684c8ca76b462a9091c45d62e8f2de9c4b1390b690eadf16/wrapt-2.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:641e94e789b5f6b4822bb8d8ebbdfc10f4e4eae7756d648b717d980f657a9eb9", size = 123064, upload-time = "2025-11-07T00:43:56.323Z" }, + { url = "https://files.pythonhosted.org/packages/0e/d1/3c1e4321fc2f5ee7fd866b2d822aa89b84495f28676fd976c47327c5b6aa/wrapt-2.0.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe21b118b9f58859b5ebaa4b130dee18669df4bd111daad082b7beb8799ad16b", size = 117403, upload-time = "2025-11-07T00:43:53.258Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b0/d2f0a413cf201c8c2466de08414a15420a25aa83f53e647b7255cc2fab5d/wrapt-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:17fb85fa4abc26a5184d93b3efd2dcc14deb4b09edcdb3535a536ad34f0b4dba", size = 121500, upload-time = "2025-11-07T00:43:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/bd/45/bddb11d28ca39970a41ed48a26d210505120f925918592283369219f83cc/wrapt-2.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b89ef9223d665ab255ae42cc282d27d69704d94be0deffc8b9d919179a609684", size = 116299, upload-time = "2025-11-07T00:43:58.877Z" }, + { url = "https://files.pythonhosted.org/packages/81/af/34ba6dd570ef7a534e7eec0c25e2615c355602c52aba59413411c025a0cb/wrapt-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a453257f19c31b31ba593c30d997d6e5be39e3b5ad9148c2af5a7314061c63eb", size = 120622, upload-time = "2025-11-07T00:43:59.962Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3e/693a13b4146646fb03254636f8bafd20c621955d27d65b15de07ab886187/wrapt-2.0.1-cp312-cp312-win32.whl", hash = "sha256:3e271346f01e9c8b1130a6a3b0e11908049fe5be2d365a5f402778049147e7e9", size = 58246, upload-time = "2025-11-07T00:44:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/a7/36/715ec5076f925a6be95f37917b66ebbeaa1372d1862c2ccd7a751574b068/wrapt-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:2da620b31a90cdefa9cd0c2b661882329e2e19d1d7b9b920189956b76c564d75", size = 60492, upload-time = "2025-11-07T00:44:01.027Z" }, + { url = "https://files.pythonhosted.org/packages/ef/3e/62451cd7d80f65cc125f2b426b25fbb6c514bf6f7011a0c3904fc8c8df90/wrapt-2.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:aea9c7224c302bc8bfc892b908537f56c430802560e827b75ecbde81b604598b", size = 58987, upload-time = "2025-11-07T00:44:02.095Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/41af4c46b5e498c90fc87981ab2972fbd9f0bccda597adb99d3d3441b94b/wrapt-2.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:47b0f8bafe90f7736151f61482c583c86b0693d80f075a58701dd1549b0010a9", size = 78132, upload-time = "2025-11-07T00:44:04.628Z" }, + { url = "https://files.pythonhosted.org/packages/1c/92/d68895a984a5ebbbfb175512b0c0aad872354a4a2484fbd5552e9f275316/wrapt-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cbeb0971e13b4bd81d34169ed57a6dda017328d1a22b62fda45e1d21dd06148f", size = 61211, upload-time = "2025-11-07T00:44:05.626Z" }, + { url = "https://files.pythonhosted.org/packages/e8/26/ba83dc5ae7cf5aa2b02364a3d9cf74374b86169906a1f3ade9a2d03cf21c/wrapt-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb7cffe572ad0a141a7886a1d2efa5bef0bf7fe021deeea76b3ab334d2c38218", size = 61689, upload-time = "2025-11-07T00:44:06.719Z" }, + { url = "https://files.pythonhosted.org/packages/cf/67/d7a7c276d874e5d26738c22444d466a3a64ed541f6ef35f740dbd865bab4/wrapt-2.0.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8d60527d1ecfc131426b10d93ab5d53e08a09c5fa0175f6b21b3252080c70a9", size = 121502, upload-time = "2025-11-07T00:44:09.557Z" }, + { url = "https://files.pythonhosted.org/packages/0f/6b/806dbf6dd9579556aab22fc92908a876636e250f063f71548a8660382184/wrapt-2.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c654eafb01afac55246053d67a4b9a984a3567c3808bb7df2f8de1c1caba2e1c", size = 123110, upload-time = "2025-11-07T00:44:10.64Z" }, + { url = "https://files.pythonhosted.org/packages/e5/08/cdbb965fbe4c02c5233d185d070cabed2ecc1f1e47662854f95d77613f57/wrapt-2.0.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:98d873ed6c8b4ee2418f7afce666751854d6d03e3c0ec2a399bb039cd2ae89db", size = 117434, upload-time = "2025-11-07T00:44:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d1/6aae2ce39db4cb5216302fa2e9577ad74424dfbe315bd6669725569e048c/wrapt-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9e850f5b7fc67af856ff054c71690d54fa940c3ef74209ad9f935b4f66a0233", size = 121533, upload-time = "2025-11-07T00:44:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/565abf57559fbe0a9155c29879ff43ce8bd28d2ca61033a3a3dd67b70794/wrapt-2.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e505629359cb5f751e16e30cf3f91a1d3ddb4552480c205947da415d597f7ac2", size = 116324, upload-time = "2025-11-07T00:44:13.28Z" }, + { url = "https://files.pythonhosted.org/packages/e1/e0/53ff5e76587822ee33e560ad55876d858e384158272cd9947abdd4ad42ca/wrapt-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2879af909312d0baf35f08edeea918ee3af7ab57c37fe47cb6a373c9f2749c7b", size = 120627, upload-time = "2025-11-07T00:44:14.431Z" }, + { url = "https://files.pythonhosted.org/packages/7c/7b/38df30fd629fbd7612c407643c63e80e1c60bcc982e30ceeae163a9800e7/wrapt-2.0.1-cp313-cp313-win32.whl", hash = "sha256:d67956c676be5a24102c7407a71f4126d30de2a569a1c7871c9f3cabc94225d7", size = 58252, upload-time = "2025-11-07T00:44:17.814Z" }, + { url = "https://files.pythonhosted.org/packages/85/64/d3954e836ea67c4d3ad5285e5c8fd9d362fd0a189a2db622df457b0f4f6a/wrapt-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9ca66b38dd642bf90c59b6738af8070747b610115a39af2498535f62b5cdc1c3", size = 60500, upload-time = "2025-11-07T00:44:15.561Z" }, + { url = "https://files.pythonhosted.org/packages/89/4e/3c8b99ac93527cfab7f116089db120fef16aac96e5f6cdb724ddf286086d/wrapt-2.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:5a4939eae35db6b6cec8e7aa0e833dcca0acad8231672c26c2a9ab7a0f8ac9c8", size = 58993, upload-time = "2025-11-07T00:44:16.65Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f4/eff2b7d711cae20d220780b9300faa05558660afb93f2ff5db61fe725b9a/wrapt-2.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a52f93d95c8d38fed0669da2ebdb0b0376e895d84596a976c15a9eb45e3eccb3", size = 82028, upload-time = "2025-11-07T00:44:18.944Z" }, + { url = "https://files.pythonhosted.org/packages/0c/67/cb945563f66fd0f61a999339460d950f4735c69f18f0a87ca586319b1778/wrapt-2.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e54bbf554ee29fcceee24fa41c4d091398b911da6e7f5d7bffda963c9aed2e1", size = 62949, upload-time = "2025-11-07T00:44:20.074Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ca/f63e177f0bbe1e5cf5e8d9b74a286537cd709724384ff20860f8f6065904/wrapt-2.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:908f8c6c71557f4deaa280f55d0728c3bca0960e8c3dd5ceeeafb3c19942719d", size = 63681, upload-time = "2025-11-07T00:44:21.345Z" }, + { url = "https://files.pythonhosted.org/packages/39/a1/1b88fcd21fd835dca48b556daef750952e917a2794fa20c025489e2e1f0f/wrapt-2.0.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e2f84e9af2060e3904a32cea9bb6db23ce3f91cfd90c6b426757cf7cc01c45c7", size = 152696, upload-time = "2025-11-07T00:44:24.318Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/d9185500c1960d9f5f77b9c0b890b7fc62282b53af7ad1b6bd779157f714/wrapt-2.0.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3612dc06b436968dfb9142c62e5dfa9eb5924f91120b3c8ff501ad878f90eb3", size = 158859, upload-time = "2025-11-07T00:44:25.494Z" }, + { url = "https://files.pythonhosted.org/packages/91/60/5d796ed0f481ec003220c7878a1d6894652efe089853a208ea0838c13086/wrapt-2.0.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d2d947d266d99a1477cd005b23cbd09465276e302515e122df56bb9511aca1b", size = 146068, upload-time = "2025-11-07T00:44:22.81Z" }, + { url = "https://files.pythonhosted.org/packages/04/f8/75282dd72f102ddbfba137e1e15ecba47b40acff32c08ae97edbf53f469e/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7d539241e87b650cbc4c3ac9f32c8d1ac8a54e510f6dca3f6ab60dcfd48c9b10", size = 155724, upload-time = "2025-11-07T00:44:26.634Z" }, + { url = "https://files.pythonhosted.org/packages/5a/27/fe39c51d1b344caebb4a6a9372157bdb8d25b194b3561b52c8ffc40ac7d1/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:4811e15d88ee62dbf5c77f2c3ff3932b1e3ac92323ba3912f51fc4016ce81ecf", size = 144413, upload-time = "2025-11-07T00:44:27.939Z" }, + { url = "https://files.pythonhosted.org/packages/83/2b/9f6b643fe39d4505c7bf926d7c2595b7cb4b607c8c6b500e56c6b36ac238/wrapt-2.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c1c91405fcf1d501fa5d55df21e58ea49e6b879ae829f1039faaf7e5e509b41e", size = 150325, upload-time = "2025-11-07T00:44:29.29Z" }, + { url = "https://files.pythonhosted.org/packages/bb/b6/20ffcf2558596a7f58a2e69c89597128781f0b88e124bf5a4cadc05b8139/wrapt-2.0.1-cp313-cp313t-win32.whl", hash = "sha256:e76e3f91f864e89db8b8d2a8311d57df93f01ad6bb1e9b9976d1f2e83e18315c", size = 59943, upload-time = "2025-11-07T00:44:33.211Z" }, + { url = "https://files.pythonhosted.org/packages/87/6a/0e56111cbb3320151eed5d3821ee1373be13e05b376ea0870711f18810c3/wrapt-2.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:83ce30937f0ba0d28818807b303a412440c4b63e39d3d8fc036a94764b728c92", size = 63240, upload-time = "2025-11-07T00:44:30.935Z" }, + { url = "https://files.pythonhosted.org/packages/1d/54/5ab4c53ea1f7f7e5c3e7c1095db92932cc32fd62359d285486d00c2884c3/wrapt-2.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:4b55cacc57e1dc2d0991dbe74c6419ffd415fb66474a02335cb10efd1aa3f84f", size = 60416, upload-time = "2025-11-07T00:44:32.002Z" }, + { url = "https://files.pythonhosted.org/packages/73/81/d08d83c102709258e7730d3cd25befd114c60e43ef3891d7e6877971c514/wrapt-2.0.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:5e53b428f65ece6d9dad23cb87e64506392b720a0b45076c05354d27a13351a1", size = 78290, upload-time = "2025-11-07T00:44:34.691Z" }, + { url = "https://files.pythonhosted.org/packages/f6/14/393afba2abb65677f313aa680ff0981e829626fed39b6a7e3ec807487790/wrapt-2.0.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ad3ee9d0f254851c71780966eb417ef8e72117155cff04821ab9b60549694a55", size = 61255, upload-time = "2025-11-07T00:44:35.762Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/a4a1f2fba205a9462e36e708ba37e5ac95f4987a0f1f8fd23f0bf1fc3b0f/wrapt-2.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d7b822c61ed04ee6ad64bc90d13368ad6eb094db54883b5dde2182f67a7f22c0", size = 61797, upload-time = "2025-11-07T00:44:37.22Z" }, + { url = "https://files.pythonhosted.org/packages/12/db/99ba5c37cf1c4fad35349174f1e38bd8d992340afc1ff27f526729b98986/wrapt-2.0.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7164a55f5e83a9a0b031d3ffab4d4e36bbec42e7025db560f225489fa929e509", size = 120470, upload-time = "2025-11-07T00:44:39.425Z" }, + { url = "https://files.pythonhosted.org/packages/30/3f/a1c8d2411eb826d695fc3395a431757331582907a0ec59afce8fe8712473/wrapt-2.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e60690ba71a57424c8d9ff28f8d006b7ad7772c22a4af432188572cd7fa004a1", size = 122851, upload-time = "2025-11-07T00:44:40.582Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8d/72c74a63f201768d6a04a8845c7976f86be6f5ff4d74996c272cefc8dafc/wrapt-2.0.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3cd1a4bd9a7a619922a8557e1318232e7269b5fb69d4ba97b04d20450a6bf970", size = 117433, upload-time = "2025-11-07T00:44:38.313Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5a/df37cf4042cb13b08256f8e27023e2f9b3d471d553376616591bb99bcb31/wrapt-2.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b4c2e3d777e38e913b8ce3a6257af72fb608f86a1df471cb1d4339755d0a807c", size = 121280, upload-time = "2025-11-07T00:44:41.69Z" }, + { url = "https://files.pythonhosted.org/packages/54/34/40d6bc89349f9931e1186ceb3e5fbd61d307fef814f09fbbac98ada6a0c8/wrapt-2.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3d366aa598d69416b5afedf1faa539fac40c1d80a42f6b236c88c73a3c8f2d41", size = 116343, upload-time = "2025-11-07T00:44:43.013Z" }, + { url = "https://files.pythonhosted.org/packages/70/66/81c3461adece09d20781dee17c2366fdf0cb8754738b521d221ca056d596/wrapt-2.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c235095d6d090aa903f1db61f892fffb779c1eaeb2a50e566b52001f7a0f66ed", size = 119650, upload-time = "2025-11-07T00:44:44.523Z" }, + { url = "https://files.pythonhosted.org/packages/46/3a/d0146db8be8761a9e388cc9cc1c312b36d583950ec91696f19bbbb44af5a/wrapt-2.0.1-cp314-cp314-win32.whl", hash = "sha256:bfb5539005259f8127ea9c885bdc231978c06b7a980e63a8a61c8c4c979719d0", size = 58701, upload-time = "2025-11-07T00:44:48.277Z" }, + { url = "https://files.pythonhosted.org/packages/1a/38/5359da9af7d64554be63e9046164bd4d8ff289a2dd365677d25ba3342c08/wrapt-2.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:4ae879acc449caa9ed43fc36ba08392b9412ee67941748d31d94e3cedb36628c", size = 60947, upload-time = "2025-11-07T00:44:46.086Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3f/96db0619276a833842bf36343685fa04f987dd6e3037f314531a1e00492b/wrapt-2.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:8639b843c9efd84675f1e100ed9e99538ebea7297b62c4b45a7042edb84db03e", size = 59359, upload-time = "2025-11-07T00:44:47.164Z" }, + { url = "https://files.pythonhosted.org/packages/71/49/5f5d1e867bf2064bf3933bc6cf36ade23505f3902390e175e392173d36a2/wrapt-2.0.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:9219a1d946a9b32bb23ccae66bdb61e35c62773ce7ca6509ceea70f344656b7b", size = 82031, upload-time = "2025-11-07T00:44:49.4Z" }, + { url = "https://files.pythonhosted.org/packages/2b/89/0009a218d88db66ceb83921e5685e820e2c61b59bbbb1324ba65342668bc/wrapt-2.0.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fa4184e74197af3adad3c889a1af95b53bb0466bced92ea99a0c014e48323eec", size = 62952, upload-time = "2025-11-07T00:44:50.74Z" }, + { url = "https://files.pythonhosted.org/packages/ae/18/9b968e920dd05d6e44bcc918a046d02afea0fb31b2f1c80ee4020f377cbe/wrapt-2.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c5ef2f2b8a53b7caee2f797ef166a390fef73979b15778a4a153e4b5fedce8fa", size = 63688, upload-time = "2025-11-07T00:44:52.248Z" }, + { url = "https://files.pythonhosted.org/packages/a6/7d/78bdcb75826725885d9ea26c49a03071b10c4c92da93edda612910f150e4/wrapt-2.0.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e042d653a4745be832d5aa190ff80ee4f02c34b21f4b785745eceacd0907b815", size = 152706, upload-time = "2025-11-07T00:44:54.613Z" }, + { url = "https://files.pythonhosted.org/packages/dd/77/cac1d46f47d32084a703df0d2d29d47e7eb2a7d19fa5cbca0e529ef57659/wrapt-2.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2afa23318136709c4b23d87d543b425c399887b4057936cd20386d5b1422b6fa", size = 158866, upload-time = "2025-11-07T00:44:55.79Z" }, + { url = "https://files.pythonhosted.org/packages/8a/11/b521406daa2421508903bf8d5e8b929216ec2af04839db31c0a2c525eee0/wrapt-2.0.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c72328f668cf4c503ffcf9434c2b71fdd624345ced7941bc6693e61bbe36bef", size = 146148, upload-time = "2025-11-07T00:44:53.388Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c0/340b272bed297baa7c9ce0c98ef7017d9c035a17a6a71dce3184b8382da2/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3793ac154afb0e5b45d1233cb94d354ef7a983708cc3bb12563853b1d8d53747", size = 155737, upload-time = "2025-11-07T00:44:56.971Z" }, + { url = "https://files.pythonhosted.org/packages/f3/93/bfcb1fb2bdf186e9c2883a4d1ab45ab099c79cbf8f4e70ea453811fa3ea7/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fec0d993ecba3991645b4857837277469c8cc4c554a7e24d064d1ca291cfb81f", size = 144451, upload-time = "2025-11-07T00:44:58.515Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6b/dca504fb18d971139d232652656180e3bd57120e1193d9a5899c3c0b7cdd/wrapt-2.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:949520bccc1fa227274da7d03bf238be15389cd94e32e4297b92337df9b7a349", size = 150353, upload-time = "2025-11-07T00:44:59.753Z" }, + { url = "https://files.pythonhosted.org/packages/1d/f6/a1de4bd3653afdf91d250ca5c721ee51195df2b61a4603d4b373aa804d1d/wrapt-2.0.1-cp314-cp314t-win32.whl", hash = "sha256:be9e84e91d6497ba62594158d3d31ec0486c60055c49179edc51ee43d095f79c", size = 60609, upload-time = "2025-11-07T00:45:03.315Z" }, + { url = "https://files.pythonhosted.org/packages/01/3a/07cd60a9d26fe73efead61c7830af975dfdba8537632d410462672e4432b/wrapt-2.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:61c4956171c7434634401db448371277d07032a81cc21c599c22953374781395", size = 64038, upload-time = "2025-11-07T00:45:00.948Z" }, + { url = "https://files.pythonhosted.org/packages/41/99/8a06b8e17dddbf321325ae4eb12465804120f699cd1b8a355718300c62da/wrapt-2.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:35cdbd478607036fee40273be8ed54a451f5f23121bd9d4be515158f9498f7ad", size = 60634, upload-time = "2025-11-07T00:45:02.087Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, +] From c801a9c9b48777551db5697ca934d9cbe0874029 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 12 Dec 2025 07:45:39 +0700 Subject: [PATCH 299/305] feat: bump action-setup-venv to use working-directory (#4098) --- action.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 9df10e82920..23acd101631 100644 --- a/action.yaml +++ b/action.yaml @@ -59,11 +59,12 @@ runs: # we just cache the venv-dir directly in action-setup-venv enable-cache: false - - uses: getsentry/action-setup-venv@0958463ee0e02b9e8aa8f8e031afae1f84b80881 # v3.0.0 + - uses: getsentry/action-setup-venv@6e8aebf461914919d9de6e3082669d6bfecc400c # v3.1.0 with: python-version: "3.12" cache-dependency-path: uv.lock install-cmd: uv sync --frozen --active + working-directory: ${{ github.action_path }} - name: Setup dev environment shell: bash From 5a7416fe0a24dca998d7b9057a49c2b6ea0e26bc Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Mon, 15 Dec 2025 18:08:19 +0000 Subject: [PATCH 300/305] release: 25.12.0 --- .env | 14 +++++++------- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/.env b/.env index d75f1814ef7..bf42b256fe7 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly -SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly -RELAY_IMAGE=ghcr.io/getsentry/relay:nightly -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly -VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.12.0 +SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.12.0 +RELAY_IMAGE=ghcr.io/getsentry/relay:25.12.0 +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.12.0 +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.12.0 +VROOM_IMAGE=ghcr.io/getsentry/vroom:25.12.0 +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.12.0 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index d6fad2e5eee..579ec5b23fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Changelog +## 25.12.0 + +### New Features ✨ + +- feat(release): Manually run post release script by @hubertdeng123 in [#4073](https://github.com/getsentry/self-hosted/pull/4073) + +- feat: bump action-setup-venv to use working-directory by @aldy505 in [#4098](https://github.com/getsentry/self-hosted/pull/4098) + +### Bug Fixes 🐛 + +- fix: Provide useful info on permission errors by @BYK in [#4096](https://github.com/getsentry/self-hosted/pull/4096) +- fix: missing 'SENTRY_SYSTEM_SECRET_KEY' declaration on Docker Compose block by @aldy505 in [#4087](https://github.com/getsentry/self-hosted/pull/4087) +- fix: grep seaweedfs bucket name instead of using awk by @aldy505 in [#4076](https://github.com/getsentry/self-hosted/pull/4076) + +### Build / dependencies / internal 🔧 + +#### Deps + +- build(deps): bump actions/create-github-app-token from 2.2.0 to 2.2.1 by @dependabot in [#4090](https://github.com/getsentry/self-hosted/pull/4090) +- build(deps): bump actions/setup-node from 4.4.0 to 6.1.0 by @dependabot in [#4091](https://github.com/getsentry/self-hosted/pull/4091) +- build(deps): bump astral-sh/setup-uv from 7.1.4 to 7.1.5 by @dependabot in [#4093](https://github.com/getsentry/self-hosted/pull/4093) + +- chore: guard unit-test.sh from being invoked by users by @aldy505 in [#4085](https://github.com/getsentry/self-hosted/pull/4085) +- chore: ask installation type on problem report template by @aldy505 in [#4086](https://github.com/getsentry/self-hosted/pull/4086) + +### Other + +- Revert "Revert "ref: migrate to uv (#4061)"" by @aldy505 in [#4097](https://github.com/getsentry/self-hosted/pull/4097) +- Revert "ref: migrate to uv (#4061)" by @BYK in [#4094](https://github.com/getsentry/self-hosted/pull/4094) +- test: integration test for user feedback by @aldy505 in [#3880](https://github.com/getsentry/self-hosted/pull/3880) +- ref: migrate to uv by @aldy505 in [#4061](https://github.com/getsentry/self-hosted/pull/4061) +- Add shm_size configuration back to postgres by @max-wittig in [#4072](https://github.com/getsentry/self-hosted/pull/4072) + ## 25.11.1 ### Build / dependencies / internal 🔧 From bd2337ba09292a1752a7abe8c5d63494ef104e91 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 16 Dec 2025 19:05:34 +0000 Subject: [PATCH 301/305] build: Set master version to nightly #skip-changelog --- .env | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env b/.env index bf42b256fe7..d75f1814ef7 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.12.0 -SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.12.0 -RELAY_IMAGE=ghcr.io/getsentry/relay:25.12.0 -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.12.0 -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.12.0 -VROOM_IMAGE=ghcr.io/getsentry/vroom:25.12.0 -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.12.0 +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From d644c9e86f489c010a0461a0cc4e6cf82d9fedb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Sv=C4=9Bdiroh?= <14951550+kostirez1@users.noreply.github.com> Date: Tue, 23 Dec 2025 13:59:15 +0100 Subject: [PATCH 302/305] chore(deps): bump seaweedfs version to 3.97 (#4120) --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 672a17f9f01..c8a5c2b047b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -244,7 +244,7 @@ services: retries: 30 seaweedfs: <<: *restart_policy - image: "chrislusf/seaweedfs:3.96_large_disk" + image: "chrislusf/seaweedfs:3.97_large_disk" entrypoint: "weed" command: >- server From 5c9794c9b1fda551f38515f85d56ec298371d060 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 23 Dec 2025 16:44:08 +0000 Subject: [PATCH 303/305] release: 25.12.1 --- .env | 14 +++++++------- CHANGELOG.md | 6 ++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.env b/.env index d75f1814ef7..fdfc10beb09 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly -SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly -RELAY_IMAGE=ghcr.io/getsentry/relay:nightly -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly -VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly +SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.12.1 +SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.12.1 +RELAY_IMAGE=ghcr.io/getsentry/relay:25.12.1 +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.12.1 +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.12.1 +VROOM_IMAGE=ghcr.io/getsentry/vroom:25.12.1 +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.12.1 HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 579ec5b23fa..d8a037fe88f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 25.12.1 + +### Build / dependencies / internal 🔧 + +- chore(deps): bump seaweedfs version to 3.97 by @kostirez1 in [#4120](https://github.com/getsentry/self-hosted/pull/4120) + ## 25.12.0 ### New Features ✨ From cd3801f0915f4b37008ecefd36714e80d6461080 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Tue, 23 Dec 2025 17:15:53 +0000 Subject: [PATCH 304/305] build: Set master version to nightly #skip-changelog --- .env | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env b/.env index fdfc10beb09..d75f1814ef7 100644 --- a/.env +++ b/.env @@ -9,13 +9,13 @@ SENTRY_EVENT_RETENTION_DAYS=90 SENTRY_BIND=9000 # Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! # SENTRY_MAIL_HOST=example.com -SENTRY_IMAGE=ghcr.io/getsentry/sentry:25.12.1 -SNUBA_IMAGE=ghcr.io/getsentry/snuba:25.12.1 -RELAY_IMAGE=ghcr.io/getsentry/relay:25.12.1 -SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:25.12.1 -TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:25.12.1 -VROOM_IMAGE=ghcr.io/getsentry/vroom:25.12.1 -UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:25.12.1 +SENTRY_IMAGE=ghcr.io/getsentry/sentry:nightly +SNUBA_IMAGE=ghcr.io/getsentry/snuba:nightly +RELAY_IMAGE=ghcr.io/getsentry/relay:nightly +SYMBOLICATOR_IMAGE=ghcr.io/getsentry/symbolicator:nightly +TASKBROKER_IMAGE=ghcr.io/getsentry/taskbroker:nightly +VROOM_IMAGE=ghcr.io/getsentry/vroom:nightly +UPTIME_CHECKER_IMAGE=ghcr.io/getsentry/uptime-checker:nightly HEALTHCHECK_INTERVAL=30s HEALTHCHECK_TIMEOUT=1m30s HEALTHCHECK_RETRIES=10 From 73971ea390b4c0e9b19c2a047ff76c4639614177 Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Mon, 5 Jan 2026 12:30:04 +0700 Subject: [PATCH 305/305] feat: switch nodestore-s3 package to getsentry org (#4119) --- sentry/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/Dockerfile b/sentry/Dockerfile index 40398a773fb..62a490e4de4 100644 --- a/sentry/Dockerfile +++ b/sentry/Dockerfile @@ -1,7 +1,7 @@ ARG SENTRY_IMAGE FROM ${SENTRY_IMAGE} -RUN pip install https://github.com/stayallive/sentry-nodestore-s3/archive/main.zip +RUN pip install https://github.com/getsentry/sentry-nodestore-s3/archive/main.zip COPY . /usr/src/sentry