Skip to content

fix: Docker sandbox agent execution + role template rendering + --model propagation for non-Claude CLIs #640

fix: Docker sandbox agent execution + role template rendering + --model propagation for non-Claude CLIs

fix: Docker sandbox agent execution + role template rendering + --model propagation for non-Claude CLIs #640

name: SonarQube PR insights comment
# Posts a sticky, advisory PR comment summarising the current Sonar
# smells / bugs / vulnerabilities for the project. This is intentionally
# a soft signal: the workflow never sets a failing check and never
# blocks merge. The Sonar scan itself runs on push to main via
# sonar-scan.yml; this comment is the operator-facing surface so a PR
# author can see "we currently sit at N smells" without leaving the PR
# tab.
#
# Skipped on fork PRs (no secret access) and when SONAR_HOST_URL is
# unset (host not configured for this repo). Both cases degrade
# silently rather than failing the workflow.
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
issues: write
pull-requests: write
concurrency:
group: sonar-pr-comment-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
comment:
name: Sonar smells delta comment
runs-on: ubuntu-latest
timeout-minutes: 5
# Skip on forks (no secret access) and when the Sonar host is
# unconfigured for this repo. Both checks keep this advisory and
# avoid noisy failures.
if: >-
${{ vars.SONAR_HOST_URL != '' &&
github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Harden runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
disable-sudo: true
- name: Query Sonar measures
id: query
env:
SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
set -euo pipefail
# Tolerate the case where the project has not been scanned
# yet: this workflow stays advisory either way.
http_code=$(curl -sS -o response.json -w '%{http_code}' \
-u "${SONAR_TOKEN}:" \
"${SONAR_HOST_URL%/}/api/measures/component?component=bernstein&metricKeys=code_smells,bugs,vulnerabilities,security_hotspots,coverage")
echo "status=${http_code}" >> "$GITHUB_OUTPUT"
if [ "${http_code}" != "200" ]; then
echo "Sonar returned ${http_code}; will post a placeholder comment."
echo '{"component":{"measures":[]}}' > response.json
fi
# Extract metrics defensively. ``jq -r`` returns ``null`` when
# absent; we coerce to ``-`` so the comment table never breaks.
extract() {
jq -r --arg k "$1" '
.component.measures
| map(select(.metric == $k))
| .[0].value // "-"
' response.json
}
{
echo "code_smells=$(extract code_smells)"
echo "bugs=$(extract bugs)"
echo "vulnerabilities=$(extract vulnerabilities)"
echo "security_hotspots=$(extract security_hotspots)"
echo "coverage=$(extract coverage)"
} >> "$GITHUB_OUTPUT"
- name: Post or update sticky comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
SONAR_STATUS: ${{ steps.query.outputs.status }}
CODE_SMELLS: ${{ steps.query.outputs.code_smells }}
BUGS: ${{ steps.query.outputs.bugs }}
VULNS: ${{ steps.query.outputs.vulnerabilities }}
HOTSPOTS: ${{ steps.query.outputs.security_hotspots }}
COVERAGE: ${{ steps.query.outputs.coverage }}
with:
github-token: ${{ github.token }}
script: |
const marker = '<!-- sonar-pr-comment:smells -->';
const prNumber = Number(process.env.PR_NUMBER);
const status = process.env.SONAR_STATUS || '';
const lines = [
marker,
'## Sonar insights (advisory, no merge-block)',
'',
status === '200'
? 'Snapshot of `bernstein` on the configured Sonar instance:'
: `Sonar query returned status ${status || 'unknown'}; this is advisory only.`,
'',
'| Metric | Value |',
'|---|---|',
`| Coverage | ${process.env.COVERAGE || '-'} |`,
`| Code smells | ${process.env.CODE_SMELLS || '-'} |`,
`| Bugs | ${process.env.BUGS || '-'} |`,
`| Vulnerabilities | ${process.env.VULNS || '-'} |`,
`| Security hotspots | ${process.env.HOTSPOTS || '-'} |`,
'',
'Run `bernstein doctor sonar` locally for the full surface.',
'',
'_This comment is a soft signal. The Sonar scan runs on push to `main`; the PR check itself never fails on smells._',
];
const body = lines.join('\n');
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
per_page: 100,
});
const existing = comments.find((c) => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
core.info(`Updated sticky sonar comment #${existing.id}.`);
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body,
});
core.info('Posted sticky sonar comment.');
}