Browse Source

resolve merge conflict

agalles/fix-actions
Amy Galles 2 months ago
parent
commit
44399d2eab
No known key found for this signature in database
GPG Key ID: 445BCEEB6E92BD
  1. 33
      .claude/CLAUDE.md
  2. 62
      .claude/README.md
  3. 78
      .claude/commands/review-pr.md
  4. 22
      .claude/prompts/review-code.md
  5. 6
      .github/templates/workflow-templates/example-references/_build.yml
  6. 2
      .github/templates/workflow-templates/example-references/_docker.yml
  7. 4
      .github/templates/workflow-templates/example-references/_test.yml
  8. 2
      .github/workflows/_publish-mobile-github-release.yml
  9. 143
      .github/workflows/_review-code.yml
  10. 50
      .github/workflows/_sonar.yml
  11. 119
      .github/workflows/respond.yml
  12. 18
      .github/workflows/review-code.yml
  13. 15
      .github/workflows/test-sonar.yml

33
.github/copilot-instructions.md → .claude/CLAUDE.md

@ -1,10 +1,11 @@
# GitHub Copilot Instructions for Bitwarden GitHub Actions # Bitwarden GitHub Actions - Claude Code Configuration
## Repository Overview ## Repository Overview
This repository contains a collection of custom GitHub Actions used by Bitwarden to simplify and standardize CI/CD pipelines across their projects. The repository follows a modular structure where each action is self-contained in its own directory with its own `action.yml` file. This repository contains a collection of custom GitHub Actions used by Bitwarden to simplify and standardize CI/CD pipelines across their projects. The repository follows a modular structure where each action is self-contained in its own directory with its own `action.yml` file.
**Repository Details:** **Repository Details:**
- **Type**: GitHub Actions collection - **Type**: GitHub Actions collection
- **Size**: Medium-sized repository with ~20 custom actions - **Size**: Medium-sized repository with ~20 custom actions
- **Languages**: TypeScript, Python, JavaScript, Shell scripts, YAML - **Languages**: TypeScript, Python, JavaScript, Shell scripts, YAML
@ -13,14 +14,17 @@ This repository contains a collection of custom GitHub Actions used by Bitwarden
## Build and Validation Instructions ## Build and Validation Instructions
### Prerequisites ### Prerequisites
- Node.js (version 22+ for TypeScript actions) - Node.js (version 22+ for TypeScript actions)
- Python 3.13+ (for Python-based actions) - Python 3.13+ (for Python-based actions)
- Docker (for containerized actions) - Docker (for containerized actions)
### Initial Setup ### Initial Setup
1. **Always run `npm install` first** in the repository root to install development dependencies including Prettier, Husky, and lint-staged. 1. **Always run `npm install` first** in the repository root to install development dependencies including Prettier, Husky, and lint-staged.
### Code Formatting and Linting ### Code Formatting and Linting
- **Code formatting**: This repository uses Prettier for all file types - **Code formatting**: This repository uses Prettier for all file types
- **Pre-commit hooks**: Husky is configured to run lint-staged on commit - **Pre-commit hooks**: Husky is configured to run lint-staged on commit
- **Command**: `npx prettier --cache --write --ignore-unknown .` (formats all files) - **Command**: `npx prettier --cache --write --ignore-unknown .` (formats all files)
@ -51,9 +55,11 @@ Refer to the [rules directory](https://github.com/bitwarden/workflow-linter/tree
**Python requirement**: Python 3.13+ with `pip install bitwarden_workflow_linter` **Python requirement**: Python 3.13+ with `pip install bitwarden_workflow_linter`
### Testing Individual Actions ### Testing Individual Actions
Each action has its own test workflow in `.github/workflows/test-*.yml`: Each action has its own test workflow in `.github/workflows/test-*.yml`:
- `test-version-bump.yml` - Tests version bumping functionality - `test-version-bump.yml` - Tests version bumping functionality
- `test-get-secrets.yml` - Tests Azure Key Vault integration - `test-get-secrets.yml` - Tests Azure Key Vault integration
- `test-download-artifacts.yml` - Tests artifact downloading - `test-download-artifacts.yml` - Tests artifact downloading
- `test-release-version-check.yml` - Tests release version validation - `test-release-version-check.yml` - Tests release version validation
- And others... - And others...
@ -61,7 +67,9 @@ Each action has its own test workflow in `.github/workflows/test-*.yml`:
**Test execution**: Tests run automatically on PRs affecting specific action directories. **Test execution**: Tests run automatically on PRs affecting specific action directories.
### TypeScript Actions Build Process ### TypeScript Actions Build Process
For TypeScript-based actions (e.g., `get-keyvault-secrets`): For TypeScript-based actions (e.g., `get-keyvault-secrets`):
1. Source files are in `src/` directory 1. Source files are in `src/` directory
2. **Always run `npm run build`** or `tsc` to compile TypeScript to JavaScript 2. **Always run `npm run build`** or `tsc` to compile TypeScript to JavaScript
3. Compiled output goes to `lib/` directory 3. Compiled output goes to `lib/` directory
@ -69,7 +77,9 @@ For TypeScript-based actions (e.g., `get-keyvault-secrets`):
5. **Critical**: Always commit both source AND compiled files 5. **Critical**: Always commit both source AND compiled files
### Docker-based Actions ### Docker-based Actions
For containerized actions (e.g., `version-bump`, `get-checksum`): For containerized actions (e.g., `version-bump`, `get-checksum`):
- Use `Dockerfile` in action directory - Use `Dockerfile` in action directory
- Python scripts use `main.py` as entry point - Python scripts use `main.py` as entry point
- **No local build required** - Docker builds during action execution - **No local build required** - Docker builds during action execution
@ -77,6 +87,7 @@ For containerized actions (e.g., `version-bump`, `get-checksum`):
## Project Layout and Architecture ## Project Layout and Architecture
### Repository Structure ### Repository Structure
``` ```
/ /
├── package.json # Root dependencies (Prettier, Husky, lint-staged) ├── package.json # Root dependencies (Prettier, Husky, lint-staged)
@ -101,15 +112,18 @@ For containerized actions (e.g., `version-bump`, `get-checksum`):
### Key Actions by Type ### Key Actions by Type
**TypeScript/Node.js Actions:** **TypeScript/Node.js Actions:**
- `get-keyvault-secrets/` - Azure Key Vault integration - `get-keyvault-secrets/` - Azure Key Vault integration
- `download-artifacts/` - Artifact management - `download-artifacts/` - Artifact management
**Python/Docker Actions:** **Python/Docker Actions:**
- `version-bump/` - File version updating (JSON, XML, PLIST, YAML) - `version-bump/` - File version updating (JSON, XML, PLIST, YAML)
- `get-checksum/` - SHA256 checksum generation - `get-checksum/` - SHA256 checksum generation
- `crowdin/` - Translation management - `crowdin/` - Translation management
**Shell/YAML Actions:** **Shell/YAML Actions:**
- `azure-login/`, `azure-logout/` - Azure authentication - `azure-login/`, `azure-logout/` - Azure authentication
- `setup-docker-trust/` - Docker configuration - `setup-docker-trust/` - Docker configuration
- Various reporting and utility actions - Various reporting and utility actions
@ -117,15 +131,18 @@ For containerized actions (e.g., `version-bump`, `get-checksum`):
### CI/CD Validation Pipeline ### CI/CD Validation Pipeline
**Pre-commit Checks:** **Pre-commit Checks:**
1. Prettier formatting (automatic via Husky) 1. Prettier formatting (automatic via Husky)
2. Lint-staged validation 2. Lint-staged validation
**Pull Request Checks:** **Pull Request Checks:**
1. Workflow linting (if `.github/workflows/` changed) 1. Workflow linting (if `.github/workflows/` changed)
2. Action-specific tests (if action directory changed) 2. Action-specific tests (if action directory changed)
3. Various security and quality scans 3. Various security and quality scans
**Critical Validation Steps:** **Critical Validation Steps:**
- **Workflow files**: Must pass `bitwarden_workflow_linter` validation - **Workflow files**: Must pass `bitwarden_workflow_linter` validation
- **TypeScript actions**: Must have compiled `lib/` output committed - **TypeScript actions**: Must have compiled `lib/` output committed
- **All files**: Must pass Prettier formatting - **All files**: Must pass Prettier formatting
@ -134,32 +151,38 @@ For containerized actions (e.g., `version-bump`, `get-checksum`):
### Dependencies and Requirements ### Dependencies and Requirements
**Development Dependencies (root):** **Development Dependencies (root):**
- `prettier` - Code formatting - `prettier` - Code formatting
- `husky` - Git hooks - `husky` - Git hooks
- `lint-staged` - Staged file processing - `lint-staged` - Staged file processing
**Action-specific Dependencies:** **Action-specific Dependencies:**
- TypeScript actions: `@actions/core`, `@actions/exec`, type definitions - TypeScript actions: `@actions/core`, `@actions/exec`, type definitions
- Python actions: Standard library primarily, some use external packages - Python actions: Standard library primarily, some use external packages
### File Patterns and Conventions ### File Patterns and Conventions
**Action Definition Files:** **Action Definition Files:**
- Every action directory MUST have an `action.yml` file - Every action directory MUST have an `action.yml` file
- Branding should include `icon` and `color` properties - Branding should include `icon` and `color` properties
- Input/output definitions follow GitHub Actions schema - Input/output definitions follow GitHub Actions schema
**TypeScript Actions:** **TypeScript Actions:**
- Source in `src/`, compiled output in `lib/` - Source in `src/`, compiled output in `lib/`
- Use `@actions/core` for GitHub Actions integration - Use `@actions/core` for GitHub Actions integration
- `tsconfig.json` for TypeScript configuration - `tsconfig.json` for TypeScript configuration
**Python Actions:** **Python Actions:**
- Main script typically named `main.py` - Main script typically named `main.py`
- Use environment variables for input (`os.getenv("INPUT_*")`) - Use environment variables for input (`os.getenv("INPUT_*")`)
- Docker-based execution via `Dockerfile` - Docker-based execution via `Dockerfile`
**Testing:** **Testing:**
- Test workflows named `test-[action-name].yml` - Test workflows named `test-[action-name].yml`
- Test fixtures in `tests/fixtures/` subdirectories - Test fixtures in `tests/fixtures/` subdirectories
- Tests validate action outputs and side effects - Tests validate action outputs and side effects
@ -169,6 +192,7 @@ For containerized actions (e.g., `version-bump`, `get-checksum`):
All code changes and action development must follow security best practices relevant to GitHub Actions and Bitwarden's standards: All code changes and action development must follow security best practices relevant to GitHub Actions and Bitwarden's standards:
**GitHub Actions Security:** **GitHub Actions Security:**
- **No hard-coded secrets or credentials** - Use secure parameter passing - **No hard-coded secrets or credentials** - Use secure parameter passing
- **Validate all action inputs** - Sanitize and validate user-provided inputs to prevent injection attacks - **Validate all action inputs** - Sanitize and validate user-provided inputs to prevent injection attacks
- **Use pinned action versions** - All external actions must be pinned to specific commit hashes (enforced by workflow linter) - **Use pinned action versions** - All external actions must be pinned to specific commit hashes (enforced by workflow linter)
@ -176,16 +200,19 @@ All code changes and action development must follow security best practices rele
- **Secure output handling** - Avoid exposing sensitive data in action outputs or logs - **Secure output handling** - Avoid exposing sensitive data in action outputs or logs
**Secret and Credential Management:** **Secret and Credential Management:**
- Use Azure Key Vault integration properly via `get-keyvault-secrets` action - Use Azure Key Vault integration properly via `get-keyvault-secrets` action
- Never log or expose secret values in action outputs - Never log or expose secret values in action outputs
- Use GitHub's secret masking capabilities (`core.setSecret()` in TypeScript actions) - Use GitHub's secret masking capabilities (`core.setSecret()` in TypeScript actions)
**Supply Chain Security:** **Supply Chain Security:**
- Only use approved actions listed in the workflow linter's approved actions list - Only use approved actions listed in the workflow linter's approved actions list
- Pin all dependencies to specific versions in `package.json` and `requirements.txt` - Pin all dependencies to specific versions in `package.json` and `requirements.txt`
- Validate Docker base images and use official, minimal images when possible - Validate Docker base images and use official, minimal images when possible
**Input Validation:** **Input Validation:**
- Validate file paths to prevent directory traversal attacks - Validate file paths to prevent directory traversal attacks
- Sanitize version strings and other user inputs - Sanitize version strings and other user inputs
- Use proper escaping when constructing shell commands - Use proper escaping when constructing shell commands
@ -195,6 +222,7 @@ All code changes and action development must follow security best practices rele
**Trust these instructions** and only perform additional searching if the information provided is incomplete or found to be incorrect. The repository follows consistent patterns, and the validation processes are well-established. **Trust these instructions** and only perform additional searching if the information provided is incomplete or found to be incorrect. The repository follows consistent patterns, and the validation processes are well-established.
**When making changes:** **When making changes:**
1. Always format code with Prettier before committing 1. Always format code with Prettier before committing
2. For TypeScript actions, always compile and commit the `lib/` output 2. For TypeScript actions, always compile and commit the `lib/` output
3. Test changes using the existing test workflows when possible 3. Test changes using the existing test workflows when possible
@ -203,6 +231,7 @@ All code changes and action development must follow security best practices rele
6. Apply security best practices and validate all inputs 6. Apply security best practices and validate all inputs
**Common pitfalls to avoid:** **Common pitfalls to avoid:**
- Forgetting to compile TypeScript actions - Forgetting to compile TypeScript actions
- Not running Prettier formatting - Not running Prettier formatting
- Missing required properties in `action.yml` files - Missing required properties in `action.yml` files

62
.claude/README.md

@ -0,0 +1,62 @@
# Claude Code Configuration
This directory contains Claude Code configuration files for the gh-actions repository.
## Directory Structure
```
.claude/
├── CLAUDE.md # General project context and guidelines
├── commands/ # Custom slash commands
│ └── review-pr.md # /review-pr command for PR reviews
└── prompts/ # Workflow-specific prompts
└── review-code.md # Used by review-code.yml workflow
```
## Custom Commands
### `/review-pr` - Pull Request Review
Triggers a comprehensive PR code review in your current Claude Code session.
**Usage:**
1. Open Claude Code in this repository
2. Check out the PR branch you want to review
3. Tag @claude and type `/review-pr`
**What it does:**
- Analyzes code quality and best practices
- Checks for security vulnerabilities
- Validates workflow linter compliance
- Reviews performance and efficiency
- Provides structured feedback with action items
**Example:**
```
@claude /review-pr
```
## Automated Workflow Reviews
The `review-code.yml` workflow uses the `.claude/prompts/review-code.md` to automatically review PRs via GitHub Actions in each Bitwarden repo. The `review-code.md` is used as a gate to execute the `review-code.yml` workflow. Repos without this file will not see Claude code reviews performed on each pull request.
**How it works:**
1. Workflow triggers on non-draft PRs
2. Reads `.claude/prompts/review-code.md` from the PR's branch
3. Posts review as a sticky comment
4. Updates comment on new commits
**To enable in our repos:**
1. Create `.claude/prompts/review-code.md` with review criteria
2. Workflow runs automatically on subsequent pull requests
## Best Practices
- **Commands** (`.claude/commands/`): For interactive Claude Code sessions
- **Prompts** (`.claude/prompts/`): For automated GitHub Actions workflows
- **CLAUDE.md**: General project context available in all Claude interactions

78
.claude/commands/review-pr.md

@ -0,0 +1,78 @@
---
description: Review the current pull request with comprehensive code analysis
---
You are conducting a thorough pull request code review for the Bitwarden gh-actions repository.
## Current Context
- Repository: bitwarden/gh-actions
- This is a collection of reusable GitHub Actions workflows and custom actions
- The code must follow Bitwarden's workflow linter rules
- Security and reliability are paramount
## Review Instructions
Perform a comprehensive review of the current PR with focus on:
### 1. **Code Quality & Best Practices**
- Adherence to GitHub Actions best practices
- Proper error handling and validation
- Code maintainability and clarity
- Appropriate use of GitHub Actions syntax
### 2. **Security Implications**
- No hardcoded secrets or credentials
- Proper permission scoping
- Input validation and sanitization
- Protection against command injection
- Safe handling of user-provided data
### 3. **Workflow Linter Compliance**
Verify compliance with Bitwarden workflow linter rules:
- Actions pinned to commit SHA with version comment
- Permissions explicitly defined
- Runner versions pinned (e.g., ubuntu-24.04)
- Proper naming conventions (capitalized)
- Only approved actions are used
### 4. **Performance & Efficiency**
- Appropriate caching strategies
- Parallel job execution where possible
- Minimal redundant operations
- Efficient use of GitHub Actions resources
### 5. **Testing & Validation**
- Adequate test coverage for new features
- Test workflows follow established patterns
- Integration with existing test infrastructure
## Output Format
Provide a structured review with:
1. **Summary of Changes**
- High-level overview of what this PR accomplishes
- Key files modified and their impact
2. **Critical Issues** (if any)
- Security vulnerabilities
- Breaking changes
- Non-compliant code that must be fixed
3. **Suggested Improvements**
- Optimization opportunities
- Better patterns or approaches
- Documentation enhancements
4. **Good Practices Observed**
- Notable positive aspects (be concise)
- Correct security implementations
- Well-structured code
5. **Action Items**
- Specific tasks for the author
- Priority level (Critical/High/Medium/Low)
Use collapsible `<details>` sections for lengthy explanations to keep the review readable.
**Important**: Focus on being thorough about issues and improvements. For good practices, be brief and just note what was done well.

22
.claude/prompts/review-code.md

@ -0,0 +1,22 @@
Please review this pull request with a focus on:
- Code quality and best practices
- Potential bugs or issues
- Security implications
- Performance considerations
Note: The PR branch is already checked out in the current working directory.
Provide a comprehensive review including:
- Summary of changes since last review
- Critical issues found (be thorough)
- Suggested improvements (be thorough)
- Good practices observed (be concise - list only the most notable items without elaboration)
- Action items for the author
- Leverage collapsible <details> sections where appropriate for lengthy explanations or code snippets to enhance human readability
When reviewing subsequent commits:
- Track status of previously identified issues (fixed/unfixed/reopened)
- Identify NEW problems introduced since last review
- Note if fixes introduced new issues
IMPORTANT: Be comprehensive about issues and improvements. For good practices, be brief - just note what was done well without explaining why or praising excessively.

6
.github/templates/workflow-templates/example-references/_build.yml

@ -25,10 +25,10 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Set up .NET - name: Set up .NET
uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0 uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
- name: Cache NuGet packages - name: Cache NuGet packages
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with: with:
path: ~/.nuget/packages path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
@ -57,7 +57,7 @@ jobs:
ls -atlh ../../ ls -atlh ../../
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: ${{ inputs.project-name }}.zip name: ${{ inputs.project-name }}.zip
path: ./${{ inputs.project-name }}.zip path: ./${{ inputs.project-name }}.zip

2
.github/templates/workflow-templates/example-references/_docker.yml

@ -72,7 +72,7 @@ jobs:
-d ${{ inputs.project-path }}/obj/build-output/publish -d ${{ inputs.project-path }}/obj/build-output/publish
- name: Build Docker image - name: Build Docker image
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with: with:
context: ${{ inputs.project-path }} context: ${{ inputs.project-path }}
file: ${{ inputs.project-path }}/Dockerfile file: ${{ inputs.project-path }}/Dockerfile

4
.github/templates/workflow-templates/example-references/_test.yml

@ -27,10 +27,10 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Set up .NET - name: Set up .NET
uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 # v4.1.0 uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
- name: Cache NuGet packages - name: Cache NuGet packages
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with: with:
path: ~/.nuget/packages path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}

2
.github/workflows/_publish-mobile-github-release.yml

@ -30,7 +30,7 @@ on:
type: boolean type: boolean
description: 'Run the workflow in dry-run mode without making any changes' description: 'Run the workflow in dry-run mode without making any changes'
required: false required: false
default: true default: false
jobs: jobs:
publish-release: publish-release:

143
.github/workflows/_review-code.yml

@ -0,0 +1,143 @@
name: Code Review
on:
workflow_call:
secrets:
AZURE_SUBSCRIPTION_ID:
required: true
AZURE_TENANT_ID:
required: true
AZURE_CLIENT_ID:
required: true
jobs:
validation:
name: Validation
runs-on: ubuntu-24.04
permissions:
contents: read
outputs:
should_review: ${{ steps.validate.outputs.should_review }}
steps:
- name: Check PR requirements
id: check-pr
env:
IS_DRAFT: ${{ github.event.pull_request.draft }}
run: |
if [ "$IS_DRAFT" == "true" ]; then
echo "⚠ Validation: PR is a draft - skipping review"
echo "pr_valid=false" >> $GITHUB_OUTPUT
else
echo "✅ Validation: PR is ready for review"
echo "pr_valid=true" >> $GITHUB_OUTPUT
fi
- name: Check if prompt file exists using GitHub CLI
id: check-prompt
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
REF: ${{ github.event.pull_request.head.sha }}
FILE_PATH: ".claude/prompts/review-code.md"
run: |
if gh api "repos/$REPO/contents/$FILE_PATH?ref=$REF" --silent 2>/dev/null; then
echo "prompt_exists=true" >> $GITHUB_OUTPUT
echo "✅ Found $FILE_PATH in $REPO"
else
echo "prompt_exists=false" >> $GITHUB_OUTPUT
echo "⚠ Validation: No $FILE_PATH found - skipping Claude review"
fi
- name: Set validation result
id: validate
env:
PR_VALID: ${{ steps.check-pr.outputs.pr_valid }}
PROMPT_EXISTS: ${{ steps.check-prompt.outputs.prompt_exists }}
run: |
if [ "$PR_VALID" == "true" ] && \
[ "$PROMPT_EXISTS" == "true" ]; then
echo "should_review=true" >> $GITHUB_OUTPUT
echo "✅ Validation passed - code review will proceed"
else
echo "should_review=false" >> $GITHUB_OUTPUT
echo "⚠ Validation failed - code review will be skipped"
fi
review:
name: Review
runs-on: ubuntu-24.04
needs: validation
if: needs.validation.outputs.should_review == 'true'
permissions:
contents: read
id-token: write
pull-requests: write
steps:
- name: Check out repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false
- name: Log in to Azure
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
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: gh-org-bitwarden
secrets: "ANTHROPIC-API-KEY"
- name: Log out from Azure
uses: bitwarden/gh-actions/azure-logout@main
- name: Build review prompt
id: build-prompt
env:
PR_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_COMMIT: ${{ github.event.pull_request.head.sha }}
run: |
PROMPT_FILE=".claude/prompts/review-code.md"
# Build the full prompt with GitHub context + repo's prompt
{
printf "REPO: %s\n" "$PR_REPO"
printf "PR NUMBER: %s\n" "$PR_NUMBER"
printf "TITLE: %s\n" "$PR_TITLE"
printf "BODY: %s\n" "$PR_BODY"
printf "AUTHOR: %s\n" "$PR_AUTHOR"
printf "COMMIT: %s\n" "$PR_COMMIT"
printf "\n"
printf "Note: The PR branch is already checked out in the current working directory.\n"
printf "\n---\n\n"
cat "$PROMPT_FILE"
} > /tmp/review-prompt.md
# Output the prompt
{
echo 'FINAL_PROMPT<<EOF'
cat /tmp/review-prompt.md
echo 'EOF'
} >> "$GITHUB_OUTPUT"
- name: Review with Claude Code
uses: anthropics/claude-code-action@e8bad572273ce919ba15fec95aef0ce974464753 # v1.0.13
with:
anthropic_api_key: ${{ steps.get-kv-secrets.outputs.ANTHROPIC-API-KEY }}
track_progress: true
use_sticky_comment: true
prompt: ${{ steps.build-prompt.outputs.FINAL_PROMPT }}
claude_args: |
--allowedTools "mcp__github_comment__update_claude_comment,mcp__github_inline_comment__create_inline_comment,Bash(gh pr diff:*),Bash(gh pr view:*)"

50
.github/workflows/_sonar.yml

@ -68,7 +68,7 @@ jobs:
args: > args: >
"-Dsonar.organization=${{ github.repository_owner }}" "-Dsonar.organization=${{ github.repository_owner }}"
"-Dsonar.projectKey=${{ github.repository_owner }}_${{ github.event.repository.name }}" "-Dsonar.projectKey=${{ github.repository_owner }}_${{ github.event.repository.name }}"
"-Dsonar.pullrequest.key=${{ github.event.pull_request.number }}" ${{ contains(github.event_name, 'pull_request') && format('"-Dsonar.pullrequest.key={0}"', github.event.pull_request.number) || '' }}
${{ inputs.sonar-test-inclusions != '' && format('"-Dsonar.test.inclusions={0}"', inputs.sonar-test-inclusions) || '' }} ${{ inputs.sonar-test-inclusions != '' && format('"-Dsonar.test.inclusions={0}"', inputs.sonar-test-inclusions) || '' }}
${{ inputs.sonar-exclusions != '' && format('"-Dsonar.exclusions={0}"', inputs.sonar-exclusions) || '' }} ${{ inputs.sonar-exclusions != '' && format('"-Dsonar.exclusions={0}"', inputs.sonar-exclusions) || '' }}
${{ inputs.sonar-sources != '' && format('"-Dsonar.sources={0}"', inputs.sonar-sources) || '' }} ${{ inputs.sonar-sources != '' && format('"-Dsonar.sources={0}"', inputs.sonar-sources) || '' }}
@ -103,30 +103,30 @@ jobs:
run: | run: |
set -euo pipefail set -euo pipefail
ARGS=() ARGS=()
if [ -n "$_PULL_REQUEST_KEY" ]; then if [ -n "${_PULL_REQUEST_KEY}" ]; then
ARGS+=("/d:sonar.pullrequest.key=$_PULL_REQUEST_KEY") ARGS+=("/d:sonar.pullrequest.key=${_PULL_REQUEST_KEY}")
fi fi
if [ -n "$_SONAR_TEST_INCLUSIONS" ]; then if [ -n "${_SONAR_TEST_INCLUSIONS}" ]; then
ARGS+=("/d:sonar.test.inclusions=$_SONAR_TEST_INCLUSIONS") ARGS+=("/d:sonar.test.inclusions=${_SONAR_TEST_INCLUSIONS}")
fi fi
if [ -n "$_SONAR_EXCLUSIONS" ]; then if [ -n "${_SONAR_EXCLUSIONS}" ]; then
ARGS+=("/d:sonar.exclusions=$_SONAR_EXCLUSIONS") ARGS+=("/d:sonar.exclusions=${_SONAR_EXCLUSIONS}")
fi fi
if [ -n "$_SONAR_SOURCES" ]; then if [ -n "${_SONAR_SOURCES}" ]; then
ARGS+=("-Dsonar.sources=$_SONAR_SOURCES") ARGS+=("-Dsonar.sources=${_SONAR_SOURCES}")
fi fi
if [ -n "$_SONAR_TESTS" ]; then if [ -n "${_SONAR_TESTS}" ]; then
ARGS+=("-Dsonar.tests=$_SONAR_TESTS") ARGS+=("-Dsonar.tests=${_SONAR_TESTS}")
fi fi
dotnet-sonarscanner begin \ dotnet-sonarscanner begin \
/k:"${REPOSITORY_OWNER}_${REPOSITORY_NAME}" \ /k:"${_REPOSITORY_OWNER}_${_REPOSITORY_NAME}" \
/o:"$REPOSITORY_OWNER" \ /o:"${_REPOSITORY_OWNER}" \
/d:sonar.token="$SONAR_TOKEN" \ /d:sonar.token="${_SONAR_TOKEN}" \
/d:sonar.host.url="https://sonarcloud.io" \ /d:sonar.host.url="https://sonarcloud.io" \
"${ARGS[@]}" "${ARGS[@]}"
dotnet build dotnet build
dotnet-sonarscanner end /d:sonar.token="$_SONAR_TOKEN" dotnet-sonarscanner end /d:sonar.token="${_SONAR_TOKEN}"
- name: Scan with Sonar - name: Scan with Sonar
if: inputs.sonar-config == 'maven' if: inputs.sonar-config == 'maven'
@ -141,20 +141,20 @@ jobs:
set -euo pipefail set -euo pipefail
ARGS=() ARGS=()
if [ -n "$_SONAR_TEST_INCLUSIONS" ]; then if [ -n "${_SONAR_TEST_INCLUSIONS}" ]; then
ARGS+=("-Dsonar.test.inclusions=$_SONAR_TEST_INCLUSIONS") ARGS+=("-Dsonar.test.inclusions=${_SONAR_TEST_INCLUSIONS}")
fi fi
if [ -n "$_SONAR_EXCLUSIONS" ]; then if [ -n "${_SONAR_EXCLUSIONS}" ]; then
ARGS+=("-Dsonar.exclusions=$_SONAR_EXCLUSIONS") ARGS+=("-Dsonar.exclusions=${_SONAR_EXCLUSIONS}")
fi fi
if [ -n "$_SONAR_SOURCES" ]; then if [ -n "${_SONAR_SOURCES}" ]; then
ARGS+=("-Dsonar.sources=$_SONAR_SOURCES") ARGS+=("-Dsonar.sources=${_SONAR_SOURCES}")
fi fi
if [ -n "$_SONAR_TESTS" ]; then if [ -n "${_SONAR_TESTS}" ]; then
ARGS+=("-Dsonar.tests=$_SONAR_TESTS") ARGS+=("-Dsonar.tests=${_SONAR_TESTS}")
fi fi
if [ -n "$_PULL_REQUEST_KEY" ]; then if [ -n "${_PULL_REQUEST_KEY}" ]; then
ARGS+=("-Dsonar.pullrequest.key=$_PULL_REQUEST_KEY") ARGS+=("-Dsonar.pullrequest.key=${_PULL_REQUEST_KEY}")
fi fi
mvn clean install -Dgpg.skip=true sonar:sonar "${ARGS[@]}" mvn clean install -Dgpg.skip=true sonar:sonar "${ARGS[@]}"

119
.github/workflows/respond.yml

@ -0,0 +1,119 @@
name: Claude Review
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
validation:
name: Validation
runs-on: ubuntu-24.04
permissions:
contents: read
outputs:
should_comment: ${{ steps.validate.outputs.should_comment }}
steps:
- name: Check GitHub event
id: check-github-event
env:
_EVENT_NAME: ${{ github.event_name }}
_COMMENT_BODY: ${{ github.event.comment.body }}
_REVIEW_BODY: ${{ github.event.review.body }}
_ISSUE_BODY: ${{ github.event.issue.body }}
run: |
# Check if @claude is mentioned in the event
MENTIONED=false
if [ "$_EVENT_NAME" == "issue_comment" ] && echo "$_COMMENT_BODY" | grep -qF "@claude"; then
MENTIONED=true
elif [ "$_EVENT_NAME" == "pull_request_review_comment" ] && echo "$_COMMENT_BODY" | grep -qF "@claude"; then
MENTIONED=true
elif [ "$_EVENT_NAME" == "pull_request_review" ] && echo "$_REVIEW_BODY" | grep -qF "@claude"; then
MENTIONED=true
elif [ "$_EVENT_NAME" == "issues" ] && echo "$_ISSUE_BODY" | grep -qF "@claude"; then
MENTIONED=true
fi
if [ "$MENTIONED" = "true" ]; then
echo "claude_mentioned=true" >> $GITHUB_OUTPUT
echo "✅ Validation: @claude mentioned in event"
else
echo "claude_mentioned=false" >> $GITHUB_OUTPUT
echo "⏭ Validation: @claude not mentioned - skipping"
fi
- name: Check for Azure credentials
id: check-azure-secret
env:
_AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
_AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
_AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
run: |
if [ -n "$_AZURE_SUBSCRIPTION_ID" ] && [ -n "$_AZURE_TENANT_ID" ] && [ -n "$_AZURE_CLIENT_ID" ]; then
echo "credentials_valid=true" >> $GITHUB_OUTPUT
echo "✅ Validation: Azure credentials available"
else
echo "credentials_valid=false" >> $GITHUB_OUTPUT
echo "⚠ Validation: Azure credentials not available"
echo "This is expected for external contributors or forks"
fi
- name: Set validation result
id: validate
run: |
if [ "${{ steps.check-github-event.outputs.claude_mentioned }}" == "true" ] && \
[ "${{ steps.check-azure-secret.outputs.credentials_valid }}" == "true" ]; then
echo "should_comment=true" >> $GITHUB_OUTPUT
echo "✅ Validation passed - comment will proceed"
else
echo "should_comment=false" >> $GITHUB_OUTPUT
echo "⚠ Validation failed - comment will be skipped"
fi
comment:
name: Claude comment
runs-on: ubuntu-24.04
needs: validation
if: needs.validation.outputs.should_comment == 'true'
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- name: Check out repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 1
- name: Log in to Azure
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
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: gh-org-bitwarden
secrets: "ANTHROPIC-API-KEY"
- name: Log out from Azure
uses: bitwarden/gh-actions/azure-logout@main
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@e8bad572273ce919ba15fec95aef0ce974464753 # v1.0.13
with:
anthropic_api_key: ${{ steps.get-kv-secrets.outputs.ANTHROPIC-API-KEY }}

18
.github/workflows/review-code.yml

@ -0,0 +1,18 @@
name: Code Review
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
jobs:
review:
name: Review
uses: bitwarden/gh-actions/.github/workflows/_review-code.yml@main
secrets:
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
permissions:
contents: read
pull-requests: write
id-token: write

15
.github/workflows/test-sonar.yml

@ -10,6 +10,17 @@ on:
branches: branches:
- "main" - "main"
workflow_dispatch: workflow_dispatch:
inputs:
sonar-config:
description: "Configuration for Sonar"
type: string
default: "default"
sonar-test-inclusions:
description: "Glob pattern(s) for test files to include in Sonar analysis"
type: string
sonar-exclusions:
description: "Glob pattern(s) for files to exclude from Sonar analysis"
type: string
permissions: {} permissions: {}
@ -25,3 +36,7 @@ jobs:
contents: read contents: read
pull-requests: write pull-requests: write
id-token: write id-token: write
with:
sonar-config: ${{ github.event.inputs.sonar-config }}
sonar-test-inclusions: ${{ github.event.inputs.sonar-test-inclusions }}
sonar-exclusions: ${{ github.event.inputs.sonar-exclusions }}

Loading…
Cancel
Save