Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions build-maven/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ inputs:
description: Maven flags for all subsequent mvn calls
default: --batch-mode --no-transfer-progress --errors --fail-at-end --show-version -Dmaven.test.redirectTestOutputToFile=false
repox-url:
description: URL for Repox
description: URL for Repox used for dependency resolution (Maven mirror)
default: https://repox.jfrog.io
repox-deploy-url:
description: URL for Repox used for artifact deployment. Defaults to SaaS Repox so deploy does not depend on edge Access Federation.
default: https://repox.jfrog.io
use-develocity:
description: Whether to use Develocity for build tracking.
Expand Down Expand Up @@ -125,6 +128,8 @@ runs:
env:
MIXED_PRIVACY: ${{ inputs.mixed-privacy }}
USER_MAVEN_ARGS: ${{ inputs.maven-args }}
ARTIFACTORY_RESOLVE_URL: ${{ format('{0}/artifactory', inputs.repox-url) }}
ARTIFACTORY_DEPLOY_URL: ${{ format('{0}/artifactory', inputs.repox-deploy-url) }}
ARTIFACTORY_DEPLOY_REPO: ${{ inputs.artifactory-deploy-repo != '' && inputs.artifactory-deploy-repo ||
(github.event.repository.visibility == 'public' || inputs.mixed-privacy == 'true') && 'sonarsource-public-qa' ||
'sonarsource-private-qa' }}
Expand All @@ -141,17 +146,21 @@ runs:
fi
echo "USER_MAVEN_ARGS=${USER_MAVEN_ARGS}"
echo "ARTIFACTORY_DEPLOY_REPO=${ARTIFACTORY_DEPLOY_REPO}"
echo "ARTIFACTORY_DEPLOY_URL=${ARTIFACTORY_DEPLOY_URL}"
echo "ARTIFACTORY_DEPLOY_USERNAME_VAULT=development/artifactory/token/{REPO_OWNER_NAME_DASH}-${ARTIFACTORY_DEPLOYER_ROLE} username | ARTIFACTORY_DEPLOY_USERNAME;"
echo "ARTIFACTORY_DEPLOY_ACCESS_TOKEN_VAULT=development/artifactory/token/{REPO_OWNER_NAME_DASH}-${ARTIFACTORY_DEPLOYER_ROLE} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN;"
} >> "$GITHUB_OUTPUT"
echo "SONARSOURCE_REPOSITORY_URL=${ARTIFACTORY_URL}/sonarsource" >> "$GITHUB_ENV"
# Downloads (Maven settings mirror) always use repox-url; uploads use ARTIFACTORY_DEPLOY_URL / repox-deploy-url.
echo "ARTIFACTORY_URL=${ARTIFACTORY_RESOLVE_URL}" >> "$GITHUB_ENV"
echo "SONARSOURCE_REPOSITORY_URL=${ARTIFACTORY_RESOLVE_URL}/sonarsource" >> "$GITHUB_ENV"
echo "Artifactory resolve (download): ${ARTIFACTORY_RESOLVE_URL}"
echo "Artifactory deploy (upload): ${ARTIFACTORY_DEPLOY_URL}"
# yamllint enable rule:line-length

- uses: SonarSource/vault-action-wrapper@881045d830534a70ec3c7c275fa3714412c8ff6e # 3.6.1
if: inputs.deploy != 'false'
id: artifactory
with:
url: ${{ contains(inputs.repox-url, 'dev.sonar.build') && 'https://vault.dev.sonar.build' || 'https://vault.sonar.build' }}
# yamllint disable rule:line-length
secrets: |
${{ inputs.deploy != 'false' && inputs.run-shadow-scans != 'true' && steps.params.outputs.ARTIFACTORY_DEPLOY_USERNAME_VAULT || '' }}
Expand Down Expand Up @@ -190,6 +199,8 @@ runs:
SONAR_PLATFORM: ${{ inputs.sonar-platform }}
RUN_SHADOW_SCANS: ${{ inputs.run-shadow-scans }}
ARTIFACTORY_DEPLOY_REPO: ${{ steps.params.outputs.ARTIFACTORY_DEPLOY_REPO }}
# Upload target for the Artifactory Maven plugin / parent POM (downloads still use SONARSOURCE_REPOSITORY_URL).
ARTIFACTORY_URL: ${{ steps.params.outputs.ARTIFACTORY_DEPLOY_URL }}

# Vault secrets
# yamllint disable rule:line-length
Expand All @@ -214,6 +225,7 @@ runs:
inputs.mixed-privacy == 'true' && steps.build.outputs.deployed == 'true' &&
(github.event_name != 'pull_request' || inputs.deploy-pull-request == 'true')
env:
ARTIFACTORY_URL: ${{ steps.params.outputs.ARTIFACTORY_DEPLOY_URL }}
ARTIFACTORY_DEPLOY_REPO: ${{ steps.params.outputs.ARTIFACTORY_DEPLOY_REPO }}
# yamllint disable rule:line-length
ARTIFACTORY_DEPLOY_ACCESS_TOKEN: ${{ steps.artifactory.outputs.vault && fromJSON(steps.artifactory.outputs.vault).ARTIFACTORY_DEPLOY_ACCESS_TOKEN || '' }}
Expand Down Expand Up @@ -246,6 +258,7 @@ runs:
if: always() && inputs.generate-summary != 'false'
shell: bash
env:
ARTIFACTORY_URL: ${{ steps.params.outputs.ARTIFACTORY_DEPLOY_URL }}
JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary
run: |
build_name="${GITHUB_REPOSITORY#*/}"
Expand Down
11 changes: 7 additions & 4 deletions build-npm/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ inputs:
description: Deprecated. Use `disable-caching` instead. Whether to cache NPM dependencies.
default: 'true'
repox-url:
description: URL for Repox
description: URL for Repox used for dependency resolution (npm registry)
default: https://repox.jfrog.io
repox-deploy-url:
description: URL for Repox used for artifact deployment. Defaults to SaaS Repox so deploy does not depend on edge Access Federation.
default: https://repox.jfrog.io
sonar-platform:
description: SonarQube primary platform (next, sqc-eu, sqc-us, or none). Use 'none' to skip sonar scans.
Expand Down Expand Up @@ -135,7 +138,6 @@ runs:
if: inputs.deploy != 'false' && inputs.run-shadow-scans != 'true'
id: artifactory
with:
url: ${{ contains(inputs.repox-url, 'dev.sonar.build') && 'https://vault.dev.sonar.build' || 'https://vault.sonar.build' }}
# yamllint disable rule:line-length
secrets: |
${{ format('development/artifactory/token/{{REPO_OWNER_NAME_DASH}}-{0} access_token | ARTIFACTORY_DEPLOY_ACCESS_TOKEN;', env.ARTIFACTORY_DEPLOYER_ROLE) }}
Expand All @@ -162,7 +164,8 @@ runs:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
BUILD_NAME: ${{ inputs.build-name || github.event.repository.name }}

ARTIFACTORY_URL: ${{ format('{0}/artifactory', inputs.repox-url) }}
# Upload target for jf npm publish (downloads still use ~/.npmrc from config-npm / repox-url).
ARTIFACTORY_URL: ${{ format('{0}/artifactory', inputs.repox-deploy-url) }}
ARTIFACTORY_DEPLOY_REPO: ${{ inputs.artifactory-deploy-repo != '' && inputs.artifactory-deploy-repo ||
(github.event.repository.visibility == 'public' && 'sonarsource-npm-public-qa' || 'sonarsource-npm-private-qa') }}
# yamllint disable rule:line-length
Expand Down Expand Up @@ -215,7 +218,7 @@ runs:
if: always() && inputs.generate-summary != 'false'
shell: bash
env:
ARTIFACTORY_URL: ${{ format('{0}/artifactory', inputs.repox-url) }}
ARTIFACTORY_URL: ${{ format('{0}/artifactory', inputs.repox-deploy-url) }}
JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR: ${{ runner.temp }}/jfrog-summary
run: |
build_name="${GITHUB_REPOSITORY#*/}"
Expand Down
9 changes: 8 additions & 1 deletion config-maven/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ runs:
if: steps.config-maven-completed.outputs.skip != 'true'
id: artifactory
with:
url: ${{ contains(inputs.repox-url, 'dev.sonar.build') && 'https://vault.dev.sonar.build' || 'https://vault.sonar.build' }}
secrets: |
development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} username | ARTIFACTORY_USERNAME;
development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} access_token | ARTIFACTORY_ACCESS_TOKEN;
Expand Down Expand Up @@ -140,6 +139,14 @@ runs:
echo "DEVELOCITY_ACCESS_KEY=${{ steps.develocity-hostname.outputs.hostname }}=$DEVELOCITY_TOKEN" >> "$GITHUB_ENV"
fi

# Temporary: Access Federation can lag when SaaS-minted tokens are used on an edge node.
- name: Wait for Artifactory token to sync
if: steps.config-maven-completed.outputs.skip != 'true'
shell: bash
env:
REPOX_URL: ${{ inputs.repox-url }}
run: "$(dirname "$ACTION_PATH_CONFIG_MAVEN")/shared/wait_artifactory_token_sync.sh"

- name: Configure Maven settings and set repository URL
if: steps.config-maven-completed.outputs.skip != 'true'
shell: bash
Expand Down
14 changes: 12 additions & 2 deletions config-npm/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ inputs:
description: Deprecated. Use `disable-caching` instead. Whether to cache NPM dependencies.
default: 'true'
repox-url:
description: URL for Repox
description: URL for Repox used for dependency resolution
default: https://repox.jfrog.io
host-actions-root:
description: Path to the actions folder on the host (used when called from another local action)
Expand Down Expand Up @@ -93,11 +93,21 @@ runs:
if: steps.config-npm-completed.outputs.skip != 'true'
id: secrets
with:
url: ${{ contains(inputs.repox-url, 'dev.sonar.build') && 'https://vault.dev.sonar.build' || 'https://vault.sonar.build' }}
secrets: |
development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} username | ARTIFACTORY_USERNAME;
development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} access_token | ARTIFACTORY_ACCESS_TOKEN;

# Temporary: Access Federation can lag when SaaS-minted tokens are used on an edge node.
- name: Wait for Artifactory token to sync
if: steps.config-npm-completed.outputs.skip != 'true'
shell: bash
env:
REPOX_URL: ${{ inputs.repox-url }}
ARTIFACTORY_URL: ${{ format('{0}/artifactory', inputs.repox-url) }}
ARTIFACTORY_USERNAME: ${{ steps.secrets.outputs.vault && fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_USERNAME || '' }}
ARTIFACTORY_ACCESS_TOKEN: ${{ steps.secrets.outputs.vault && fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_ACCESS_TOKEN || '' }}
run: "$(dirname "$ACTION_PATH_CONFIG_NPM")/shared/wait_artifactory_token_sync.sh"

- name: Configure NPM authentication
if: steps.config-npm-completed.outputs.skip != 'true'
shell: bash
Expand Down
14 changes: 12 additions & 2 deletions config-uv/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ inputs:
description: Name of the uv index in pyproject.toml to authenticate (e.g. repox for `[[tool.uv.index]]` with `name = "repox"`)
default: repox
repox-url:
description: URL for Repox
description: URL for Repox used for dependency resolution
default: https://repox.jfrog.io
uv-cache-dir:
description: Path to the uv cache directory, relative to GitHub workspace
Expand Down Expand Up @@ -106,11 +106,21 @@ runs:
if: steps.config-uv-completed.outputs.skip != 'true'
id: secrets
with:
url: ${{ contains(inputs.repox-url, 'dev.sonar.build') && 'https://vault.dev.sonar.build' || 'https://vault.sonar.build' }}
secrets: |
development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} username | ARTIFACTORY_USERNAME;
development/artifactory/token/{REPO_OWNER_NAME_DASH}-${{ env.ARTIFACTORY_READER_ROLE }} access_token | ARTIFACTORY_ACCESS_TOKEN;

# Temporary: Access Federation can lag when SaaS-minted tokens are used on an edge node.
- name: Wait for Artifactory token to sync
if: steps.config-uv-completed.outputs.skip != 'true'
shell: bash
env:
REPOX_URL: ${{ inputs.repox-url }}
ARTIFACTORY_URL: ${{ format('{0}/artifactory', inputs.repox-url) }}
ARTIFACTORY_USERNAME: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_USERNAME }}
ARTIFACTORY_ACCESS_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).ARTIFACTORY_ACCESS_TOKEN }}
run: "$(dirname "$ACTION_PATH_CONFIG_UV")/shared/wait_artifactory_token_sync.sh"

- name: Configure uv authentication
if: steps.config-uv-completed.outputs.skip != 'true'
shell: bash
Expand Down
53 changes: 53 additions & 0 deletions shared/wait_artifactory_token_sync.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/bash
# Wait until a SaaS-minted Artifactory token is accepted by an edge node.
#
# /api/system/ping is anonymous; use a protected storage API that validates the token.
#
# Required environment variables:
# - ARTIFACTORY_URL: Artifactory base URL (…/artifactory)
# - ARTIFACTORY_USERNAME: Artifactory username
# - ARTIFACTORY_ACCESS_TOKEN: Artifactory access token
#
# Optional:
# - REPOX_URL: Instance URL used to skip the wait for SaaS (jfrog.io)

set -euo pipefail

REPOX_URL="${REPOX_URL:-${ARTIFACTORY_URL:-}}"
if [[ "$REPOX_URL" == *jfrog.io* ]]; then
echo "Skipping token sync wait for SaaS Repox ($REPOX_URL)"
exit 0
fi

if [[ -z "${ARTIFACTORY_URL:-}" || -z "${ARTIFACTORY_USERNAME:-}" || -z "${ARTIFACTORY_ACCESS_TOKEN:-}" ]]; then
echo "::error title=Missing Artifactory credentials::Cannot wait for token sync without credentials"
exit 1
fi

check_url="${ARTIFACTORY_URL%/}/api/storage/sonarsource-qa"
max_attempts=60
sleep_seconds=5
attempt=0

echo "Waiting for Artifactory token federation sync at $check_url (up to $((max_attempts * sleep_seconds))s)"

while true; do
attempt=$((attempt + 1))
http_code="$(curl -sS -o /dev/null -w '%{http_code}' \
-u "${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}" \
"$check_url" || echo "000")"
Comment on lines +36 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Quality: curl retry lacks connect/max timeout

The polling curl has no --connect-timeout/--max-time, so a hung TCP connection to the edge node would stall an iteration indefinitely rather than counting as a failed attempt, defeating the 5-minute bound. Add --connect-timeout 5 --max-time 15 to keep each attempt time-boxed.

Bound each curl attempt so a stalled connection can't hang the loop.:

http_code="$(curl -sS --connect-timeout 5 --max-time 15 -o /dev/null -w '%{http_code}' \
  -u "${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}" \
  "$check_url" || echo "000")"
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +36 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Quality: curl failure appends duplicate http_code output

On a connection failure curl still emits its -w '%{http_code}' value (000) to stdout, and then || echo "000" appends another, so http_code becomes e.g. 000000, producing confusing log lines like HTTP 000000. Logic still works, but drop the trailing || echo "000" (or capture into a temp and default) so the reported code stays clean.

Was this helpful? React with 👍 / 👎


if [[ "$http_code" == "200" ]]; then
echo "Artifactory accepted credentials after ${attempt} attempt(s) (HTTP 200)"
exit 0
fi

if (( attempt >= max_attempts )); then
echo "::error title=Artifactory token sync timeout::Credentials were not accepted by $check_url" \
"within $((max_attempts * sleep_seconds))s (last HTTP ${http_code})"
exit 1
fi

echo "Attempt ${attempt}/${max_attempts}: HTTP ${http_code}, retrying in ${sleep_seconds}s..."
sleep "$sleep_seconds"
done
Loading