Skip to content
Merged
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
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1376,9 +1376,19 @@ After running this action, the following environment variables are available:

Verify that SonarQube SCA (Software Composition Analysis) ran for the project.

The action discovers project keys from `.sonarlint/connectedMode.json`, `sonar-project.properties`, `pom.xml`, `build.gradle(.kts)`, and
`GITHUB_REPOSITORY`, then polls the Next, SonarCloud US, and SonarCloud EU instances. It fails if SCA data is missing on every
platform after the timeout.
The action discovers project keys from `.github/repo-metadata.yaml`, `.sonarlint/connectedMode.json`, `sonar-project.properties`,
`pom.xml`, `build.gradle(.kts)`, and `GITHUB_REPOSITORY`, then polls the Next, SonarCloud US, and SonarCloud EU instances. It fails
if SCA data is missing on every platform after the timeout.

### Manually setting the project key for the check

For repos that don't have standard SonarQube config files (e.g. repos using SonarCloud Automatic Analysis), create
`.github/repo-metadata.yaml` with the project key under the `check-sca` section:

```yaml
check-sca:
project-key: your-project-key
```

### Requirements

Expand Down
44 changes: 36 additions & 8 deletions check-sca/check-sca.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ PLATFORMS=(
"sqc-eu:SQC_EU_URL:SQC_EU_TOKEN"
)

# Parse a key=value property from a file. Returns the trimmed value or empty string.
parse_property_value() {
local file="$1" key="$2"
grep -E "^${key}=" "$file" | head -1 | cut -d= -f2- | tr -d '[:space:]'
Comment thread
sonar-review-alpha[bot] marked this conversation as resolved.
}

# Read a value from .github/repo-metadata.yaml under a given top-level section.
# Usage: read_repo_metadata <file> <section> <key>
# Example: read_repo_metadata repo-metadata.yaml "check-sca" "project-key"
read_repo_metadata() {
local file="$1" section="$2" key="$3"
sed -n "/^${section}:/,/^[^ ]/{ /^ ${key}:/{ s/^ ${key}:[ ]*//; s/^['\"]//; s/['\"]$//; p; q; }; }" "$file" | tr -d '[:space:]'
}

# Discover candidate SonarQube project keys from config files.
# Returns one key per line, deduplicated, in priority order.
discover_project_keys() {
Expand All @@ -45,7 +59,21 @@ discover_project_keys() {
keys+=("$PROJECT_KEY_INPUT")
Comment thread
bwalsh434 marked this conversation as resolved.
fi

# 2. .sonarlint/connectedMode.json
# 2. .github/repo-metadata.yaml or .yml (always at repo root, not working-directory)
local repo_root="${GITHUB_WORKSPACE:-$work_dir}"
local metadata_file
for metadata_file in "$repo_root/.github/repo-metadata.yaml" "$repo_root/.github/repo-metadata.yml"; do
if [[ -f "$metadata_file" ]]; then
local key
key=$(read_repo_metadata "$metadata_file" "check-sca" "project-key")
if [[ -n "$key" ]]; then
keys+=("$key")
fi
break
fi
done

# 3. .sonarlint/connectedMode.json
local sonarlint_file="$work_dir/.sonarlint/connectedMode.json"
if [[ -f "$sonarlint_file" ]]; then
local key
Expand All @@ -55,20 +83,20 @@ discover_project_keys() {
fi
fi

# 3. sonar-project.properties
# 4. sonar-project.properties
local sonar_props="$work_dir/sonar-project.properties"
if [[ -f "$sonar_props" ]]; then
local key
key=$(grep -E '^sonar\.projectKey=' "$sonar_props" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '[:space:]')
key=$(parse_property_value "$sonar_props" 'sonar\.projectKey')
if [[ -n "$key" ]]; then
keys+=("$key")
fi
fi

# 4. pom.xml
# 5. pom.xml
local pom_file="$work_dir/pom.xml"
if [[ -f "$pom_file" ]]; then
# 4a. Explicit sonar.projectKey property (highest priority within pom.xml)
# 5a. Explicit sonar.projectKey property (highest priority within pom.xml)
local key
key=$(perl -0777 -ne '
if (/<sonar\.projectKey>([^<]+)/s) {
Expand All @@ -81,7 +109,7 @@ discover_project_keys() {
keys+=("$key")
fi

# 4b. Derive groupId:artifactId (Maven default project key)
# 5b. Derive groupId:artifactId (Maven default project key)
local maven_key
maven_key=$(perl -0777 -ne '
sub trim {
Expand Down Expand Up @@ -111,7 +139,7 @@ discover_project_keys() {
fi
fi

# 5. build.gradle / build.gradle.kts
# 6. build.gradle / build.gradle.kts
local gradle_file
for gradle_file in "$work_dir/build.gradle" "$work_dir/build.gradle.kts"; do
if [[ -f "$gradle_file" ]]; then
Expand All @@ -129,7 +157,7 @@ discover_project_keys() {
fi
done

# 6. Derive from GITHUB_REPOSITORY (e.g. SonarSource/repo-name -> SonarSource_repo-name)
# 7. Derive from GITHUB_REPOSITORY (e.g. SonarSource/repo-name -> SonarSource_repo-name)
if [[ -n "${GITHUB_REPOSITORY:-}" ]]; then
local derived_key="${GITHUB_REPOSITORY/\//_}"
keys+=("$derived_key")
Expand Down
86 changes: 83 additions & 3 deletions spec/check-sca_spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ Describe 'discover_project_keys()'
setup() {
TEST_DIR=$(mktemp -d)
export WORKING_DIRECTORY="$TEST_DIR"
export GITHUB_WORKSPACE="$TEST_DIR"
return 0
}
# shellcheck disable=SC2329 # Function invoked indirectly by AfterEach
teardown() {
rm -rf "$TEST_DIR"
unset GITHUB_WORKSPACE
return 0
}

Expand All @@ -74,6 +76,81 @@ Describe 'discover_project_keys()'
The output should include "FromSonarlint"
End

It 'reads from .github/repo-metadata.yaml'
export PROJECT_KEY_INPUT=""
mkdir -p "$TEST_DIR/.github"
printf 'check-sca:\n project-key: FromMetadata\n' > "$TEST_DIR/.github/repo-metadata.yaml"
When call discover_project_keys
The output should include "FromMetadata"
End

Comment thread
bwalsh434 marked this conversation as resolved.
It 'reads from .github/repo-metadata.yml'
export PROJECT_KEY_INPUT=""
mkdir -p "$TEST_DIR/.github"
printf 'check-sca:\n project-key: FromYml\n' > "$TEST_DIR/.github/repo-metadata.yml"
When call discover_project_keys
The output should include "FromYml"
End

It 'prefers .yaml over .yml when both exist'
export PROJECT_KEY_INPUT=""
export GITHUB_REPOSITORY=""
mkdir -p "$TEST_DIR/.github"
printf 'check-sca:\n project-key: FromYaml\n' > "$TEST_DIR/.github/repo-metadata.yaml"
printf 'check-sca:\n project-key: FromYml\n' > "$TEST_DIR/.github/repo-metadata.yml"
When call discover_project_keys
The line 1 should equal "FromYaml"
End

It 'reads quoted values from .github/repo-metadata.yaml'
export PROJECT_KEY_INPUT=""
mkdir -p "$TEST_DIR/.github"
printf 'check-sca:\n project-key: "QuotedKey"\n' > "$TEST_DIR/.github/repo-metadata.yaml"
When call discover_project_keys
The output should include "QuotedKey"
End

It 'ignores .github/repo-metadata.yaml when check-sca section is missing'
export PROJECT_KEY_INPUT=""
export GITHUB_REPOSITORY=""
mkdir -p "$TEST_DIR/.github"
printf 'jira:\n project-key: BUILD\n' > "$TEST_DIR/.github/repo-metadata.yaml"
When call discover_project_keys
The output should equal ""
End

It 'prioritizes .github/repo-metadata.yaml over sonar-project.properties'
export PROJECT_KEY_INPUT=""
export GITHUB_REPOSITORY=""
mkdir -p "$TEST_DIR/.github"
printf 'check-sca:\n project-key: FromMetadata\n' > "$TEST_DIR/.github/repo-metadata.yaml"
echo "sonar.projectKey=FromProperties" > "$TEST_DIR/sonar-project.properties"
When call discover_project_keys
The line 1 should equal "FromMetadata"
The line 2 should equal "FromProperties"
End

It 'keeps both explicit input and .github/repo-metadata.yaml keys'
export PROJECT_KEY_INPUT="explicit-key"
mkdir -p "$TEST_DIR/.github"
printf 'check-sca:\n project-key: FromMetadata\n' > "$TEST_DIR/.github/repo-metadata.yaml"
When call discover_project_keys
The line 1 should equal "explicit-key"
The line 2 should equal "FromMetadata"
End

It 'reads .github/repo-metadata.yaml from repo root when working-directory is a subdirectory'
export PROJECT_KEY_INPUT=""
export GITHUB_REPOSITORY=""
export GITHUB_WORKSPACE="$TEST_DIR"
mkdir -p "$TEST_DIR/.github"
printf 'check-sca:\n project-key: RootKey\n' > "$TEST_DIR/.github/repo-metadata.yaml"
mkdir -p "$TEST_DIR/services/my-app"
export WORKING_DIRECTORY="$TEST_DIR/services/my-app"
When call discover_project_keys
The output should include "RootKey"
End

It 'reads from sonar-project.properties'
export PROJECT_KEY_INPUT=""
echo "sonar.projectKey=FromProperties" > "$TEST_DIR/sonar-project.properties"
Expand Down Expand Up @@ -164,15 +241,18 @@ Describe 'discover_project_keys()'

It 'returns keys from multiple sources in priority order'
export PROJECT_KEY_INPUT="explicit-key"
mkdir -p "$TEST_DIR/.github"
printf 'check-sca:\n project-key: metadata-key\n' > "$TEST_DIR/.github/repo-metadata.yaml"
mkdir -p "$TEST_DIR/.sonarlint"
echo '{"projectKey": "sonarlint-key"}' > "$TEST_DIR/.sonarlint/connectedMode.json"
echo "sonar.projectKey=props-key" > "$TEST_DIR/sonar-project.properties"
export GITHUB_REPOSITORY="SonarSource/test-repo"
When call discover_project_keys
The line 1 should equal "explicit-key"
The line 2 should equal "sonarlint-key"
The line 3 should equal "props-key"
The line 4 should equal "SonarSource_test-repo"
The line 2 should equal "metadata-key"
The line 3 should equal "sonarlint-key"
The line 4 should equal "props-key"
The line 5 should equal "SonarSource_test-repo"
End

It 'returns empty when no sources available'
Expand Down
Loading