From 97a2be72296d11ce75955fd8e96c7939b2cba4f7 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:11:01 +0000 Subject: [PATCH 1/5] Add maintainer-run integration connectivity check workflow Co-Authored-By: Andreas Igel --- .github/workflows/integrations-check.yml | 80 ++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 .github/workflows/integrations-check.yml diff --git a/.github/workflows/integrations-check.yml b/.github/workflows/integrations-check.yml new file mode 100644 index 00000000..84da8635 --- /dev/null +++ b/.github/workflows/integrations-check.yml @@ -0,0 +1,80 @@ +name: 'Integration connectivity check' + +# Maintainer-only diagnostic: verify the 3rd-party integration secrets and their +# endpoints are usable, without building or running any project/PR code. +# +# workflow_dispatch can only be started by users with write access, from the +# default branch, so it is inherently maintainer-gated and never runs for fork +# PRs. It performs authenticated HTTP checks only; token values are never +# printed. This is a diagnostic and does not replace the fork-ci environment +# approval that gates the actual Sonar publish. +on: + workflow_dispatch: + inputs: + target: + description: 'Which integration(s) to check' + required: true + default: all + type: choice + options: + - all + - sonarcloud + - codecov + +permissions: + contents: read + +concurrency: + group: integrations-check-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + TARGET: ${{ github.event.inputs.target }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + steps: + - name: Check SonarCloud token and connectivity + if: env.TARGET == 'all' || env.TARGET == 'sonarcloud' + run: | + set -euo pipefail + if [ -z "${SONAR_TOKEN:-}" ]; then + echo "::error::SONAR_TOKEN secret is empty or not configured." + exit 1 + fi + # Validate the token via SonarCloud's authentication endpoint. The token + # is sent as HTTP basic-auth username; its value is never printed. + http_code="$(curl -sS -o /tmp/sonar.json -w '%{http_code}' \ + -u "$SONAR_TOKEN:" https://sonarcloud.io/api/authentication/validate || true)" + echo "sonarcloud.io/api/authentication/validate -> HTTP $http_code" + if [ "$http_code" != "200" ]; then + echo "::error::SonarCloud returned HTTP $http_code (token likely invalid/expired, or the API is unreachable)." + exit 1 + fi + if ! grep -q '"valid":true' /tmp/sonar.json; then + echo "::error::SonarCloud reports the token as NOT valid." + cat /tmp/sonar.json + exit 1 + fi + echo "OK: SONAR_TOKEN is valid and SonarCloud is reachable." + + - name: Check Codecov token and connectivity + if: env.TARGET == 'all' || env.TARGET == 'codecov' + run: | + set -euo pipefail + if [ -z "${CODECOV_TOKEN:-}" ]; then + echo "::error::CODECOV_TOKEN secret is empty or not configured." + exit 1 + fi + # Codecov upload tokens have no public "validate" endpoint, so this is a + # presence + reachability check against the Codecov API (stated honestly). + http_code="$(curl -sS -o /dev/null -w '%{http_code}' https://api.codecov.io/health || true)" + echo "api.codecov.io/health -> HTTP $http_code" + if [ "$http_code" != "200" ]; then + echo "::error::Codecov API not reachable (HTTP $http_code)." + exit 1 + fi + echo "OK: CODECOV_TOKEN is present and the Codecov API is reachable (upload-token validity is not publicly verifiable)." From 2d3b80265c23629a98da34e47e79087140cc263c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:23:11 +0000 Subject: [PATCH 2/5] Use RUNNER_TEMP and a token-protected Codecov endpoint in connectivity check Co-Authored-By: Andreas Igel --- .github/workflows/integrations-check.yml | 39 ++++++++++++++++-------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/.github/workflows/integrations-check.yml b/.github/workflows/integrations-check.yml index 84da8635..5d265405 100644 --- a/.github/workflows/integrations-check.yml +++ b/.github/workflows/integrations-check.yml @@ -47,16 +47,17 @@ jobs: fi # Validate the token via SonarCloud's authentication endpoint. The token # is sent as HTTP basic-auth username; its value is never printed. - http_code="$(curl -sS -o /tmp/sonar.json -w '%{http_code}' \ + body="$RUNNER_TEMP/sonar-validate.json" + http_code="$(curl -sS -o "$body" -w '%{http_code}' \ -u "$SONAR_TOKEN:" https://sonarcloud.io/api/authentication/validate || true)" echo "sonarcloud.io/api/authentication/validate -> HTTP $http_code" if [ "$http_code" != "200" ]; then echo "::error::SonarCloud returned HTTP $http_code (token likely invalid/expired, or the API is unreachable)." exit 1 fi - if ! grep -q '"valid":true' /tmp/sonar.json; then + if ! grep -q '"valid":true' "$body"; then echo "::error::SonarCloud reports the token as NOT valid." - cat /tmp/sonar.json + cat "$body" exit 1 fi echo "OK: SONAR_TOKEN is valid and SonarCloud is reachable." @@ -69,12 +70,26 @@ jobs: echo "::error::CODECOV_TOKEN secret is empty or not configured." exit 1 fi - # Codecov upload tokens have no public "validate" endpoint, so this is a - # presence + reachability check against the Codecov API (stated honestly). - http_code="$(curl -sS -o /dev/null -w '%{http_code}' https://api.codecov.io/health || true)" - echo "api.codecov.io/health -> HTTP $http_code" - if [ "$http_code" != "200" ]; then - echo "::error::Codecov API not reachable (HTTP $http_code)." - exit 1 - fi - echo "OK: CODECOV_TOKEN is present and the Codecov API is reachable (upload-token validity is not publicly verifiable)." + # Exercise the token against a token-protected Codecov endpoint (the + # repo detail in API v2). A 200 means the token authenticates and can + # read this repo; 401/403 means the token is rejected; other codes are + # reachability/other errors. The token is sent only in the auth header. + body="$RUNNER_TEMP/codecov-repo.json" + url="https://api.codecov.io/api/v2/github/${GITHUB_REPOSITORY%/*}/repos/${GITHUB_REPOSITORY#*/}/" + http_code="$(curl -sS -o "$body" -w '%{http_code}' \ + -H "Authorization: bearer $CODECOV_TOKEN" "$url" || true)" + echo "api.codecov.io/api/v2/github/.../repos/... -> HTTP $http_code" + case "$http_code" in + 200) + echo "OK: CODECOV_TOKEN authenticates and can read this repo on Codecov." ;; + 401|403) + echo "::error::Codecov rejected the token (HTTP $http_code) - it is invalid, expired, or lacks access to this repo." + exit 1 ;; + 404) + echo "::error::Codecov returned 404 - the token authenticated but the repo is not set up on Codecov (or the token lacks visibility)." + exit 1 ;; + *) + echo "::error::Unexpected response from Codecov (HTTP $http_code) - likely a reachability/service issue." + cat "$body" || true + exit 1 ;; + esac From acdad7cdf8506e1e2525da491ef9a3d83e5a4ac0 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:27:27 +0000 Subject: [PATCH 3/5] Select Codecov token type (upload/api) and use matching endpoint Co-Authored-By: Andreas Igel --- .github/workflows/integrations-check.yml | 44 ++++++++++++++++++------ 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/.github/workflows/integrations-check.yml b/.github/workflows/integrations-check.yml index 5d265405..7b4d993a 100644 --- a/.github/workflows/integrations-check.yml +++ b/.github/workflows/integrations-check.yml @@ -20,6 +20,14 @@ on: - all - sonarcloud - codecov + codecov_token_type: + description: 'What kind of secret CODECOV_TOKEN holds' + required: true + default: upload + type: choice + options: + - upload + - api permissions: contents: read @@ -34,6 +42,7 @@ jobs: timeout-minutes: 10 env: TARGET: ${{ github.event.inputs.target }} + CODECOV_TOKEN_TYPE: ${{ github.event.inputs.codecov_token_type }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} steps: @@ -70,18 +79,31 @@ jobs: echo "::error::CODECOV_TOKEN secret is empty or not configured." exit 1 fi - # Exercise the token against a token-protected Codecov endpoint (the - # repo detail in API v2). A 200 means the token authenticates and can - # read this repo; 401/403 means the token is rejected; other codes are - # reachability/other errors. The token is sent only in the auth header. - body="$RUNNER_TEMP/codecov-repo.json" - url="https://api.codecov.io/api/v2/github/${GITHUB_REPOSITORY%/*}/repos/${GITHUB_REPOSITORY#*/}/" - http_code="$(curl -sS -o "$body" -w '%{http_code}' \ - -H "Authorization: bearer $CODECOV_TOKEN" "$url" || true)" - echo "api.codecov.io/api/v2/github/.../repos/... -> HTTP $http_code" + owner="${GITHUB_REPOSITORY%/*}" + repo="${GITHUB_REPOSITORY#*/}" + body="$RUNNER_TEMP/codecov.json" + if [ "$CODECOV_TOKEN_TYPE" = "api" ]; then + # API access token: read the repo detail via API v2. The token is + # sent only in the auth header; its value is never printed. + url="https://api.codecov.io/api/v2/github/$owner/repos/$repo/" + http_code="$(curl -sS -o "$body" -w '%{http_code}' \ + -H "Authorization: bearer $CODECOV_TOKEN" "$url" || true)" + echo "GET api.codecov.io/api/v2/github/.../repos/... -> HTTP $http_code" + else + # Upload token: exercise the first step of Codecov's upload handshake + # (create-commit) against the real HEAD commit. This is the same call + # the uploader makes, so a valid token accepts it; the token is sent + # only in the auth header. + url="https://api.codecov.io/upload/github/$owner::::$repo/commits" + http_code="$(curl -sS -o "$body" -w '%{http_code}' -X POST \ + -H "Authorization: token $CODECOV_TOKEN" \ + -H 'Content-Type: application/json' \ + -d "{\"commitid\":\"$GITHUB_SHA\"}" "$url" || true)" + echo "POST api.codecov.io/upload/github/.../commits -> HTTP $http_code" + fi case "$http_code" in - 200) - echo "OK: CODECOV_TOKEN authenticates and can read this repo on Codecov." ;; + 200|201) + echo "OK: CODECOV_TOKEN authenticates against Codecov." ;; 401|403) echo "::error::Codecov rejected the token (HTTP $http_code) - it is invalid, expired, or lacks access to this repo." exit 1 ;; From bf60674cf58fbf1ca14ee18bcb1f47854b2dc4d2 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:30:41 +0000 Subject: [PATCH 4/5] Drop token-type input; check Codecov upload token via upload handshake Co-Authored-By: Andreas Igel --- .github/workflows/integrations-check.yml | 38 +++++++----------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/.github/workflows/integrations-check.yml b/.github/workflows/integrations-check.yml index 7b4d993a..04316cef 100644 --- a/.github/workflows/integrations-check.yml +++ b/.github/workflows/integrations-check.yml @@ -20,14 +20,6 @@ on: - all - sonarcloud - codecov - codecov_token_type: - description: 'What kind of secret CODECOV_TOKEN holds' - required: true - default: upload - type: choice - options: - - upload - - api permissions: contents: read @@ -42,7 +34,6 @@ jobs: timeout-minutes: 10 env: TARGET: ${{ github.event.inputs.target }} - CODECOV_TOKEN_TYPE: ${{ github.event.inputs.codecov_token_type }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} steps: @@ -82,25 +73,16 @@ jobs: owner="${GITHUB_REPOSITORY%/*}" repo="${GITHUB_REPOSITORY#*/}" body="$RUNNER_TEMP/codecov.json" - if [ "$CODECOV_TOKEN_TYPE" = "api" ]; then - # API access token: read the repo detail via API v2. The token is - # sent only in the auth header; its value is never printed. - url="https://api.codecov.io/api/v2/github/$owner/repos/$repo/" - http_code="$(curl -sS -o "$body" -w '%{http_code}' \ - -H "Authorization: bearer $CODECOV_TOKEN" "$url" || true)" - echo "GET api.codecov.io/api/v2/github/.../repos/... -> HTTP $http_code" - else - # Upload token: exercise the first step of Codecov's upload handshake - # (create-commit) against the real HEAD commit. This is the same call - # the uploader makes, so a valid token accepts it; the token is sent - # only in the auth header. - url="https://api.codecov.io/upload/github/$owner::::$repo/commits" - http_code="$(curl -sS -o "$body" -w '%{http_code}' -X POST \ - -H "Authorization: token $CODECOV_TOKEN" \ - -H 'Content-Type: application/json' \ - -d "{\"commitid\":\"$GITHUB_SHA\"}" "$url" || true)" - echo "POST api.codecov.io/upload/github/.../commits -> HTTP $http_code" - fi + # CODECOV_TOKEN is the repo upload token: exercise the first step of + # Codecov's upload handshake (create-commit) against the real HEAD + # commit. This is the same call the uploader makes, so a valid token + # accepts it; the token is sent only in the auth header (never printed). + url="https://api.codecov.io/upload/github/$owner::::$repo/commits" + http_code="$(curl -sS -o "$body" -w '%{http_code}' -X POST \ + -H "Authorization: token $CODECOV_TOKEN" \ + -H 'Content-Type: application/json' \ + -d "{\"commitid\":\"$GITHUB_SHA\"}" "$url" || true)" + echo "POST api.codecov.io/upload/github/.../commits -> HTTP $http_code" case "$http_code" in 200|201) echo "OK: CODECOV_TOKEN authenticates against Codecov." ;; From d84b9cbb626edbc57c3641a13b47ab72b2ff5d23 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:38:25 +0000 Subject: [PATCH 5/5] Clarify Codecov 404 handling for upload endpoint Co-Authored-By: Andreas Igel --- .github/workflows/integrations-check.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integrations-check.yml b/.github/workflows/integrations-check.yml index 04316cef..73ca73d0 100644 --- a/.github/workflows/integrations-check.yml +++ b/.github/workflows/integrations-check.yml @@ -90,7 +90,11 @@ jobs: echo "::error::Codecov rejected the token (HTTP $http_code) - it is invalid, expired, or lacks access to this repo." exit 1 ;; 404) - echo "::error::Codecov returned 404 - the token authenticated but the repo is not set up on Codecov (or the token lacks visibility)." + # The upload endpoint returns 404 "Repository not found" both for an + # invalid/unauthorized upload token and for a repo not activated on + # Codecov (it does not disclose which, by design). + echo "::error::Codecov returned 404 'Repository not found' - the upload token is invalid/unauthorized, or the repo is not activated on Codecov." + cat "$body" || true exit 1 ;; *) echo "::error::Unexpected response from Codecov (HTTP $http_code) - likely a reachability/service issue."