commit e24004415e4a4e72d0419408dc323b534b344589 Author: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Wed May 6 15:10:48 2026 -0400 Add Claude Code review and compliance audit workflows - Reusable PR review workflow (repos call via thin wrapper) - Weekly compliance audit across all org repos - Rollout script to push wrapper workflow to all repos - Uses GitHub App tokens for cross-repo auth (no PAT rotation needed) diff --git a/.github/workflows/claude-code-review.yaml b/.github/workflows/claude-code-review.yaml new file mode 100644 index 0000000..a068bc9 --- /dev/null +++ b/.github/workflows/claude-code-review.yaml @@ -0,0 +1,32 @@ +name: Claude Code Review + +on: + workflow_call: + secrets: + anthropic_api_key: + required: true + +permissions: + contents: read + pull-requests: write + +jobs: + claude-review: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: anthropics/claude-code-action@v1 + with: + anthropic_api_key: ${{ secrets.anthropic_api_key }} + review_comments: "true" + direct_prompt: | + Review this pull request. Focus on: + - Code correctness and potential bugs + - Security issues (hardcoded secrets, injection, OWASP top 10) + - Sea Haven conventions: kebab-case resource names, secrets in AWS Secrets Manager (not env vars), Lambda defaults (Python 3.12+, arm64, explicit 60-day log retention) + - README accuracy if changed + Post findings as inline review comments. Be concise — flag real issues, skip nitpicks. diff --git a/.github/workflows/compliance-audit.yaml b/.github/workflows/compliance-audit.yaml new file mode 100644 index 0000000..bd47e6b --- /dev/null +++ b/.github/workflows/compliance-audit.yaml @@ -0,0 +1,106 @@ +name: Compliance Audit + +on: + schedule: + - cron: "0 14 * * 1" # Every Monday at 10am ET (14:00 UTC) + workflow_dispatch: + +jobs: + get-repos: + runs-on: ubuntu-latest + outputs: + repos: ${{ steps.list.outputs.repos }} + steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.CLAUDE_CI_APP_ID }} + private-key: ${{ secrets.CLAUDE_CI_APP_PRIVATE_KEY }} + owner: Sea-Haven-Industries + + - name: List org repos + id: list + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + repos=$(gh repo list Sea-Haven-Industries \ + --no-archived \ + --json name \ + --jq '[.[].name] | @json' \ + --limit 100) + echo "repos=$repos" >> "$GITHUB_OUTPUT" + + audit: + needs: get-repos + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + max-parallel: 3 + matrix: + repo: ${{ fromJson(needs.get-repos.outputs.repos) }} + steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.CLAUDE_CI_APP_ID }} + private-key: ${{ secrets.CLAUDE_CI_APP_PRIVATE_KEY }} + owner: Sea-Haven-Industries + repositories: ${{ matrix.repo }} + + - name: Checkout repo + uses: actions/checkout@v4 + with: + repository: Sea-Haven-Industries/${{ matrix.repo }} + token: ${{ steps.app-token.outputs.token }} + + - name: Run compliance audit + uses: anthropics/claude-code-action@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + direct_prompt: | + Audit this repository for Sea Haven Industries compliance. Check each item and report pass/fail: + + **Naming:** + - All resource names in IaC templates use kebab-case (no snake_case or PascalCase) + - Stack name matches repo name + + **Secrets:** + - No secrets in Lambda environment variables + - No secrets in SSM Parameter Store (should be in Secrets Manager) + - No hardcoded API keys, tokens, or credentials in source code + - Secret names follow `stack-name/secret-name` convention + + **Lambda defaults (if applicable):** + - Runtime is Python 3.12+ or Node 22.x + - Architecture is arm64 + - Log retention is explicitly set to 60 days in the IaC template + + **Project hygiene:** + - README exists and describes the project architecture + - .gitignore exists and covers .env, .aws-sam/, __pycache__ + - samconfig.toml is gitignored (samconfig.toml.example committed if SAM project) + - CloudFormation outputs include function ARNs and URLs + + Output a concise markdown report. Only flag actual violations — don't report items that don't apply (e.g., skip Lambda checks if no Lambdas exist). + + - name: Create issue if violations found + if: failure() + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + existing=$(gh issue list \ + --repo "Sea-Haven-Industries/${{ matrix.repo }}" \ + --label "compliance" \ + --state open \ + --json number \ + --jq 'length') + if [ "$existing" -eq 0 ]; then + gh issue create \ + --repo "Sea-Haven-Industries/${{ matrix.repo }}" \ + --title "Compliance audit: violations found" \ + --body "The weekly compliance audit found violations in this repo. Check the [latest audit run](https://github.com/Sea-Haven-Industries/.github/actions/workflows/compliance-audit.yaml) for details." \ + --label "compliance" + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be47843 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +.env diff --git a/README.md b/README.md new file mode 100644 index 0000000..fd36bf2 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# .github + +Organization-level GitHub configuration for Sea Haven Industries. + +## What's in here + +### Reusable Workflows + +**`.github/workflows/claude-code-review.yaml`** — Reusable PR review workflow powered by Claude Code. Individual repos call this via a thin wrapper workflow. Reviews for code correctness, security issues, and Sea Haven conventions (kebab-case, secrets placement, Lambda defaults). + +**`.github/workflows/compliance-audit.yaml`** — Scheduled weekly audit (Mondays 10am ET) that checks all org repos for compliance with Sea Haven conventions. Creates GitHub issues on repos with violations. Can also be triggered manually via `workflow_dispatch`. + +### Scripts + +**`scripts/rollout-review-workflow.sh`** — One-time script to push the thin PR review wrapper workflow to all org repos via the GitHub API. Creates a branch and PR on each repo. + +## Setup + +### 1. Create a GitHub App + +1. Go to **Organization Settings > Developer settings > GitHub Apps > New GitHub App** +2. Name it `claude-code-ci` (or similar) +3. Set Homepage URL to your org URL +4. Disable Webhook (uncheck "Active") +5. Set these **Repository permissions:** + - **Contents:** Read and write + - **Issues:** Read and write + - **Metadata:** Read-only + - **Pull requests:** Read and write +6. Set **Where can this app be installed?** to "Only on this account" +7. Click **Create GitHub App** +8. Note the **App ID** from the app's settings page +9. Under **Private keys**, click **Generate a private key** — save the `.pem` file + +### 2. Install the App + +1. From the app's settings page, click **Install App** +2. Select `Sea-Haven-Industries` +3. Choose **All repositories** + +### 3. Add org-level secrets + +Go to **Organization Settings > Secrets and variables > Actions** and add: + +| Secret | Value | +|--------|-------| +| `ANTHROPIC_API_KEY` | Your Claude API key | +| `CLAUDE_CI_APP_ID` | The App ID from step 1 | +| `CLAUDE_CI_APP_PRIVATE_KEY` | The full contents of the `.pem` file from step 1 | + +### 4. Roll out PR reviews to repos + +```bash +./scripts/rollout-review-workflow.sh +``` + +This creates a PR on each repo adding the thin wrapper workflow. Review and merge them, then delete the `add-claude-review` branches. diff --git a/scripts/rollout-review-workflow.sh b/scripts/rollout-review-workflow.sh new file mode 100755 index 0000000..b654f73 --- /dev/null +++ b/scripts/rollout-review-workflow.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -euo pipefail + +ORG="Sea-Haven-Industries" +BRANCH="add-claude-review" +WORKFLOW_PATH=".github/workflows/claude-review.yaml" +COMMIT_MSG="Add Claude Code review workflow" + +WORKFLOW_CONTENT='name: Claude Code Review + +on: + pull_request: + types: [opened, synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + review: + uses: Sea-Haven-Industries/.github/.github/workflows/claude-code-review.yaml@main + secrets: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} +' + +SKIP_REPOS=(".github") + +should_skip() { + local repo="$1" + for skip in "${SKIP_REPOS[@]}"; do + if [[ "$repo" == "$skip" ]]; then + return 0 + fi + done + return 1 +} + +echo "Fetching non-archived repos from $ORG..." +repos=$(gh repo list "$ORG" --no-archived --json name --jq '.[].name' --limit 100) + +for repo in $repos; do + if should_skip "$repo"; then + echo "SKIP $repo (in skip list)" + continue + fi + + echo "" + echo "--- $repo ---" + + existing=$(gh api "repos/$ORG/$repo/contents/$WORKFLOW_PATH" --jq '.sha' 2>/dev/null || true) + if [[ -n "$existing" ]]; then + echo "SKIP $repo (workflow already exists)" + continue + fi + + default_branch=$(gh api "repos/$ORG/$repo" --jq '.default_branch') + + encoded=$(echo -n "$WORKFLOW_CONTENT" | base64) + + gh api "repos/$ORG/$repo/git/refs" \ + -f "ref=refs/heads/$BRANCH" \ + -f "sha=$(gh api "repos/$ORG/$repo/git/ref/heads/$default_branch" --jq '.object.sha')" \ + 2>/dev/null || true + + gh api "repos/$ORG/$repo/contents/$WORKFLOW_PATH" \ + -X PUT \ + -f "message=$COMMIT_MSG" \ + -f "content=$encoded" \ + -f "branch=$BRANCH" \ + > /dev/null + + pr_url=$(gh pr create \ + --repo "$ORG/$repo" \ + --base "$default_branch" \ + --head "$BRANCH" \ + --title "$COMMIT_MSG" \ + --body "Adds a thin workflow that delegates PR reviews to the central reusable workflow in \`Sea-Haven-Industries/.github\`. Requires the \`ANTHROPIC_API_KEY\` org secret to be set." \ + 2>/dev/null || echo "PR already exists") + + echo "DONE $repo → $pr_url" +done + +echo "" +echo "Rollout complete. Review and merge the PRs, then delete the feature branches."