mirror of
https://github.com/bitwarden/android.git
synced 2026-10-22 02:53:19 -05:00
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
190 lines
9.0 KiB
YAML
190 lines
9.0 KiB
YAML
name: SDLC / SDK Update Evaluation
|
|
|
|
on:
|
|
pull_request:
|
|
types: [opened, synchronize]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
|
|
cancel-in-progress: true
|
|
|
|
permissions: {}
|
|
|
|
jobs:
|
|
evaluate:
|
|
name: Evaluate SDK Update
|
|
runs-on: ubuntu-24.04
|
|
if: ${{ github.event.pull_request.head.ref == 'sdlc/sdk-update' }}
|
|
permissions:
|
|
id-token: write
|
|
actions: read
|
|
contents: write
|
|
packages: read
|
|
pull-requests: write
|
|
|
|
steps:
|
|
- name: Skip if this bump was already evaluated
|
|
id: gate
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
REPO: ${{ github.repository }}
|
|
run: |
|
|
LATEST_SUBJECT=$(gh pr view "$PR_NUMBER" -R "$REPO" --json commits --jq '.commits[-1].messageHeadline')
|
|
if [[ "$LATEST_SUBJECT" != "SDK Update - "* ]]; then
|
|
echo "Branch tip is not a fresh SDK version bump ('$LATEST_SUBJECT') — already evaluated, skipping."
|
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Log in to Azure
|
|
if: steps.gate.outputs.skip == 'false'
|
|
uses: bitwarden/gh-actions/azure-login@main
|
|
with:
|
|
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
|
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
|
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
|
|
|
- name: Get Azure Key Vault secrets
|
|
id: get-kv-secrets
|
|
if: steps.gate.outputs.skip == 'false'
|
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
|
with:
|
|
keyvault: gh-org-bitwarden
|
|
secrets: "ANTHROPIC-RESPONSE-API-KEY,BW-GHAPP-ID,BW-GHAPP-KEY"
|
|
|
|
- name: Log out from Azure
|
|
if: steps.gate.outputs.skip == 'false'
|
|
uses: bitwarden/gh-actions/azure-logout@main
|
|
|
|
- name: Generate GH App token
|
|
if: steps.gate.outputs.skip == 'false'
|
|
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
|
id: app-token
|
|
with:
|
|
client-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }}
|
|
private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }}
|
|
permission-contents: write
|
|
permission-pull-requests: write
|
|
|
|
- name: Check out repo
|
|
if: steps.gate.outputs.skip == 'false'
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
token: ${{ steps.app-token.outputs.token }}
|
|
ref: ${{ github.event.pull_request.head.sha }}
|
|
fetch-depth: 0
|
|
persist-credentials: true
|
|
|
|
- name: Clone sdk-internal
|
|
if: steps.gate.outputs.skip == 'false'
|
|
run: git clone --quiet https://github.com/bitwarden/sdk-internal "${{ github.workspace }}/../sdk-internal"
|
|
|
|
- name: Setup Android Build
|
|
if: steps.gate.outputs.skip == 'false'
|
|
uses: ./.github/actions/setup-android-build
|
|
|
|
- name: Pre-fetch the SDK artifact
|
|
if: steps.gate.outputs.skip == 'false'
|
|
# claude-code-action replaces GITHUB_TOKEN in the environment it hands Claude's Bash
|
|
# tool, so Gradle cannot authenticate to GitHub Packages from there. Resolving the
|
|
# dependency here populates ~/.gradle/caches, letting Claude's own compile read the
|
|
# fixed SDK version straight from cache. continue-on-error keeps a genuine compile
|
|
# break reaching Claude, which is the evaluation this workflow exists to perform.
|
|
continue-on-error: true
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: ./gradlew app:compileStandardDebugKotlin authenticator:compileDebugKotlin
|
|
|
|
- name: Verify the SDK artifact reached the Gradle cache
|
|
if: steps.gate.outputs.skip == 'false'
|
|
# A cold cache reaches Claude as a dependency-resolution error it could mistake for a
|
|
# break the SDK bump caused, so fail here where the cause is unambiguous. Metadata
|
|
# alone does not let the compile run, hence the check for the .aar rather than the dir.
|
|
run: |
|
|
version=$(sed -n 's/^bitwardenSdk = "\([^"]*\)"/\1/p' gradle/libs.versions.toml)
|
|
if [ -z "$version" ]; then
|
|
echo "::error::Could not read bitwardenSdk from gradle/libs.versions.toml."
|
|
exit 1
|
|
fi
|
|
|
|
cache_root="${GRADLE_USER_HOME:-$HOME/.gradle}/caches/modules-2/files-2.1"
|
|
artifact=$(find "$cache_root/com.bitwarden/sdk-android/$version" \
|
|
-name '*.aar' -print -quit 2>/dev/null || true)
|
|
if [ -z "$artifact" ]; then
|
|
echo "::error::sdk-android $version is absent from the Gradle cache; the pre-fetch did not resolve it."
|
|
exit 1
|
|
fi
|
|
|
|
echo "Cached sdk-android $version at $artifact"
|
|
|
|
- name: Run Claude Code
|
|
id: claude
|
|
if: steps.gate.outputs.skip == 'false'
|
|
uses: anthropics/claude-code-action@be7b93b1907a4abad570368f3c74b6fe3807510b # v1.0.183
|
|
with:
|
|
anthropic_api_key: ${{ steps.get-kv-secrets.outputs.ANTHROPIC-RESPONSE-API-KEY }}
|
|
allowed_bots: "bw-ghapp"
|
|
bot_id: "178206702"
|
|
bot_name: "bw-ghapp[bot]"
|
|
track_progress: true
|
|
use_sticky_comment: true
|
|
plugin_marketplaces: "https://github.com/bitwarden/ai-plugins.git"
|
|
plugins: |
|
|
bitwarden-delivery-tools@bitwarden-marketplace
|
|
bitwarden-software-engineer@bitwarden-marketplace
|
|
prompt: |
|
|
PR #${{ github.event.pull_request.number }} in ${{ github.repository }} bumps the
|
|
Bitwarden SDK. Evaluate it yourself using the `evaluating-sdk-internal-updates`
|
|
skill's Identify steps (1-7). `bitwarden/sdk-internal` is already cloned as a sibling
|
|
directory at `${{ github.workspace }}/../sdk-internal`, satisfying step 1's
|
|
prerequisite — use it directly.
|
|
|
|
If step 7 turns up anything to resolve, dispatch a single subagent on the
|
|
`bitwarden-software-engineer` agent to invoke `Skill(evaluating-sdk-internal-updates)`
|
|
itself and carry out its Resolve steps (8-10) for every finding in one pass — decide
|
|
the fix, implement it, and commit on the current branch (already checked out) using
|
|
`Skill(bitwarden-delivery-tools:committing-changes)` for the message. Hand the
|
|
subagent all the findings (commit, symbol, call sites for each) so it doesn't redo the
|
|
investigation, dispatching it once for every finding rather than once per finding. Do
|
|
not push; the workflow pushes separately. Have it report back the commit SHA and each
|
|
finding's disposition. Skip the subagent entirely if step 7 finds nothing to resolve.
|
|
|
|
Once the subagent has reported back — or immediately, if there was nothing to resolve —
|
|
update the sticky PR comment yourself with the step 7 report,
|
|
structured as: "## SDK bump evaluated" (old → new version, commit count), "## Compile-time
|
|
breaks" (found-and-fixed, or "none found"), "## Runtime considerations" (any behavioral
|
|
notes worth flagging, or omit the section if there are none), "## Everything else in
|
|
range — confirmed safe" (brief, one line per commit or group), and "## Commit" (the SHA,
|
|
or "no commit — nothing needed fixing"). Always post this, even when the conclusion is
|
|
that nothing needs fixing — the comment is the audit trail that the check ran.
|
|
claude_args: |
|
|
--model opus
|
|
--allowedTools "Agent,Bash(gh pr diff:*),Bash(git -C * log *),Bash(git -C * show *),Bash(git add:*),Bash(git commit:*),Bash(git log:*),Bash(git show:*),Bash(git diff:*),Bash(grep:*),Bash(./gradlew *),Read,Grep,Glob,Edit,Write,Skill,mcp__github_comment__update_claude_comment"
|
|
|
|
- name: Push any resolved fix
|
|
if: steps.gate.outputs.skip == 'false'
|
|
env:
|
|
_BRANCH_NAME: ${{ github.event.pull_request.head.ref }}
|
|
run: |
|
|
# claude-code-action treats the PR head as untrusted and restores these exact paths from
|
|
# origin/main before running Claude, regardless of whether this branch's copy is stale.
|
|
# This job never has a legitimate reason to change them, so a diff here is that restore,
|
|
# not Claude — exclude them rather than flag it.
|
|
_TRUSTED_CONFIG_PATHSPEC=(
|
|
':!.claude' ':!.mcp.json' ':!.claude.json' ':!.gitmodules' ':!.ripgreprc'
|
|
':!CLAUDE.md' ':!CLAUDE.local.md' ':!.husky'
|
|
)
|
|
if [ -n "$(git status --porcelain -- . "${_TRUSTED_CONFIG_PATHSPEC[@]}")" ]; then
|
|
echo "::error::Claude left uncommitted changes; nothing was pushed."
|
|
git status --porcelain -- . "${_TRUSTED_CONFIG_PATHSPEC[@]}"
|
|
exit 1
|
|
fi
|
|
|
|
if git diff --quiet "origin/$_BRANCH_NAME" HEAD; then
|
|
echo "No new commits to push."
|
|
else
|
|
git push origin "HEAD:$_BRANCH_NAME"
|
|
fi
|