feat: add Gradle and Maven support with Surefire parser (75-90% savings) #253
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| branches: [develop, master] | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| # ─── Fast gates (fail early, save CI minutes) ─── | |
| fmt: | |
| name: fmt | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt | |
| - run: cargo fmt --all -- --check | |
| clippy: | |
| name: clippy | |
| needs: fmt | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy | |
| - uses: Swatinem/rust-cache@v2 | |
| - run: cargo clippy --all-targets | |
| # ─── Parallel gates (all need code to compile) ─── | |
| test: | |
| name: test (${{ matrix.os }}) | |
| needs: clippy | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - run: cargo test --all | |
| security: | |
| name: Security Scan | |
| needs: clippy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Install cargo-audit | |
| run: cargo install cargo-audit | |
| - name: Cargo Audit (CVE check) | |
| run: | | |
| echo "## Security Scan Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Dependency Vulnerabilities" >> $GITHUB_STEP_SUMMARY | |
| if cargo audit 2>&1 | tee audit.log; then | |
| echo "No known vulnerabilities detected" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "Vulnerabilities found:" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| cat audit.log >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "::warning::Dependency vulnerabilities detected - review required" | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| - name: Critical files check | |
| run: | | |
| echo "### Critical Files Modified" >> $GITHUB_STEP_SUMMARY | |
| CRITICAL=$(git diff --name-only origin/master...HEAD | grep -E "(runner|summary|tracking|init|pnpm_cmd|container)\.rs|Cargo\.toml|workflows/.*\.yml" || true) | |
| if [ -n "$CRITICAL" ]; then | |
| echo "**HIGH RISK**: The following critical files were modified:" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "$CRITICAL" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Required Actions:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Manual security review by 2 maintainers" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Verify no shell injection vectors" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Check input validation remains intact" >> $GITHUB_STEP_SUMMARY | |
| echo "::warning::Critical RTK files modified - enhanced review required" | |
| else | |
| echo "No critical files modified" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| - name: Dangerous patterns scan | |
| run: | | |
| echo "### Dangerous Code Patterns" >> $GITHUB_STEP_SUMMARY | |
| PATTERNS=$(git diff origin/master...HEAD | grep -E "Command::new\(\"sh\"|Command::new\(\"bash\"|\.env\(\"LD_PRELOAD|\.env\(\"PATH|reqwest::|std::net::|TcpStream|UdpSocket|unsafe \{|\.unwrap\(\) |panic!\(|todo!\(|unimplemented!\(" || true) | |
| if [ -n "$PATTERNS" ]; then | |
| echo "**Potentially dangerous patterns detected:**" >> $GITHUB_STEP_SUMMARY | |
| echo '```diff' >> $GITHUB_STEP_SUMMARY | |
| echo "$PATTERNS" | head -30 >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Security Concerns:**" >> $GITHUB_STEP_SUMMARY | |
| echo "$PATTERNS" | grep -q "Command::new" && echo "- Shell command execution detected" >> $GITHUB_STEP_SUMMARY || true | |
| echo "$PATTERNS" | grep -q "\.env\(\"" && echo "- Environment variable manipulation" >> $GITHUB_STEP_SUMMARY || true | |
| echo "$PATTERNS" | grep -q "reqwest::\|std::net::\|TcpStream\|UdpSocket" && echo "- Network operations added" >> $GITHUB_STEP_SUMMARY || true | |
| echo "$PATTERNS" | grep -q "unsafe" && echo "- Unsafe code blocks" >> $GITHUB_STEP_SUMMARY || true | |
| echo "$PATTERNS" | grep -q "\.unwrap\(\)\|panic!\(" && echo "- Panic-inducing code" >> $GITHUB_STEP_SUMMARY || true | |
| echo "::warning::Dangerous code patterns detected - manual review required" | |
| else | |
| echo "No dangerous patterns detected" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| - name: New dependencies check | |
| run: | | |
| echo "### Dependencies Changes" >> $GITHUB_STEP_SUMMARY | |
| if git diff origin/master...HEAD Cargo.toml | grep -E "^\+.*=" | grep -v "^\+\+\+" > new_deps.txt; then | |
| echo "**New dependencies added:**" >> $GITHUB_STEP_SUMMARY | |
| echo '```toml' >> $GITHUB_STEP_SUMMARY | |
| cat new_deps.txt >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Required Actions:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Audit each new dependency on crates.io" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Check maintainer reputation and download counts" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Verify no typosquatting (e.g., 'reqwest' vs 'request')" >> $GITHUB_STEP_SUMMARY | |
| echo "::warning::New dependencies require supply chain audit" | |
| else | |
| echo "No new dependencies added" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| - name: Clippy security lints | |
| run: | | |
| echo "### Clippy Security Lints" >> $GITHUB_STEP_SUMMARY | |
| if cargo clippy --all-targets -- -W clippy::unwrap_used -W clippy::panic -W clippy::expect_used 2>&1 | tee clippy.log | grep -E "warning:|error:"; then | |
| echo "Security-related lints triggered:" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| grep -E "warning:|error:" clippy.log | head -20 >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "::warning::Clippy security lints failed" | |
| else | |
| echo "All security lints passed" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: Summary verdict | |
| run: | | |
| echo "---" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Security Review Verdict" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**This is an automated security scan. A human maintainer must:**" >> $GITHUB_STEP_SUMMARY | |
| echo "1. Review all warnings above" >> $GITHUB_STEP_SUMMARY | |
| echo "2. Verify PR intent matches actual code changes" >> $GITHUB_STEP_SUMMARY | |
| echo "3. Check for subtle backdoors or logic bombs" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**For high-risk PRs (critical files modified):**" >> $GITHUB_STEP_SUMMARY | |
| echo "- Require approval from 2 maintainers" >> $GITHUB_STEP_SUMMARY | |
| echo "- Test in isolated environment before merge" >> $GITHUB_STEP_SUMMARY | |
| benchmark: | |
| name: benchmark | |
| needs: clippy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build rtk | |
| run: cargo build --release | |
| - name: Install Python tools | |
| run: pip install ruff pytest | |
| - name: Install Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: 'stable' | |
| - name: Install Go tools | |
| run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest | |
| - name: Run benchmark | |
| run: ./scripts/benchmark.sh | |
| # ─── AI Doc Review: develop PRs only ─── | |
| doc-review: | |
| name: doc review | |
| if: github.base_ref == 'develop' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Gather PR context | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR_NUM=${{ github.event.pull_request.number }} | |
| gh pr diff "$PR_NUM" --name-only > changed_files.txt | |
| gh pr diff "$PR_NUM" | head -c 12000 > diff.txt | |
| gh pr view "$PR_NUM" --json title,body --jq '"PR Title: \(.title)\nPR Description: \(.body)"' > pr_info.txt | |
| - name: Build prompt files | |
| run: | | |
| # System prompt | |
| cat <<'EOF' > system_prompt.txt | |
| You are a documentation reviewer for the RTK project. | |
| You will receive the project's CONTRIBUTING.md (which contains the documentation rules), the PR info, changed files, and diff. | |
| Your job: based ONLY on the documentation rules in CONTRIBUTING.md, decide if the PR includes the required documentation updates. | |
| IMPORTANT: | |
| - CI/CD changes, test-only changes, and refactors with no user-facing impact do NOT require doc updates. | |
| - Be practical, not pedantic. Small obvious fixes don't need CHANGELOG entries. | |
| - Only flag missing docs when there is a clear user-facing change. | |
| EOF | |
| # User prompt: concatenate files (no printf, no variable expansion issues) | |
| { | |
| cat pr_info.txt | |
| echo "" | |
| echo "---" | |
| echo "CONTRIBUTING.md:" | |
| cat CONTRIBUTING.md | |
| echo "" | |
| echo "---" | |
| echo "Changed files:" | |
| cat changed_files.txt | |
| echo "" | |
| echo "---" | |
| echo "Diff (may be truncated):" | |
| cat diff.txt | |
| } > user_prompt.txt | |
| - name: AI documentation review | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.RTK_DOCS_ANTHROPIC_KEY }} | |
| run: | | |
| echo "## Documentation Review (AI)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ -z "$ANTHROPIC_API_KEY" ]; then | |
| echo "::warning::ANTHROPIC_API_KEY not configured — skipping AI doc review" | |
| echo "Skipped: ANTHROPIC_API_KEY secret not configured." >> $GITHUB_STEP_SUMMARY | |
| exit 0 | |
| fi | |
| echo "::group::Preparing API request" | |
| echo "System prompt: $(wc -c < system_prompt.txt) bytes" | |
| echo "User prompt: $(wc -c < user_prompt.txt) bytes" | |
| SYSTEM_JSON=$(jq -Rs . < system_prompt.txt) | |
| USER_JSON=$(jq -Rs . < user_prompt.txt) | |
| echo "::endgroup::" | |
| echo "::group::Calling Claude API (claude-sonnet-4-6)" | |
| RESPONSE=$(curl -s -w "\n%{http_code}" https://api.anthropic.com/v1/messages \ | |
| -H "content-type: application/json" \ | |
| -H "x-api-key: $ANTHROPIC_API_KEY" \ | |
| -H "anthropic-version: 2023-06-01" \ | |
| -d "{ | |
| \"model\": \"claude-sonnet-4-6\", | |
| \"max_tokens\": 1024, | |
| \"messages\": [{\"role\": \"user\", \"content\": $USER_JSON}], | |
| \"system\": $SYSTEM_JSON, | |
| \"output_config\": { | |
| \"format\": { | |
| \"type\": \"json_schema\", | |
| \"schema\": { | |
| \"type\": \"object\", | |
| \"properties\": { | |
| \"status\": {\"type\": \"string\", \"enum\": [\"PASS\", \"FAIL\"]}, | |
| \"reasoning\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}}, | |
| \"files_to_update\": {\"type\": \"array\", \"items\": {\"type\": \"string\"}} | |
| }, | |
| \"required\": [\"status\", \"reasoning\", \"files_to_update\"], | |
| \"additionalProperties\": false | |
| } | |
| } | |
| } | |
| }") | |
| HTTP_CODE=$(echo "$RESPONSE" | tail -1) | |
| BODY=$(echo "$RESPONSE" | sed '$d') | |
| echo "HTTP status: $HTTP_CODE" | |
| echo "::endgroup::" | |
| if [ "$HTTP_CODE" != "200" ]; then | |
| echo "::warning::Claude API returned HTTP $HTTP_CODE — skipping doc review" | |
| echo "Skipped: API error (HTTP $HTTP_CODE)" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "$BODY" | head -10 >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| exit 0 | |
| fi | |
| # Parse structured JSON response | |
| REVIEW_JSON=$(echo "$BODY" | jq -r '.content[0].text // empty') | |
| if [ -z "$REVIEW_JSON" ]; then | |
| echo "::warning::Empty response from Claude API — skipping doc review" | |
| echo "Skipped: empty API response" >> $GITHUB_STEP_SUMMARY | |
| echo "Raw response:" | |
| echo "$BODY" | head -20 | |
| exit 0 | |
| fi | |
| echo "::group::AI Review Result" | |
| echo "$REVIEW_JSON" | jq . | |
| echo "::endgroup::" | |
| STATUS=$(echo "$REVIEW_JSON" | jq -r '.status') | |
| REASONING=$(echo "$REVIEW_JSON" | jq -r '.reasoning[]' 2>/dev/null) | |
| FILES=$(echo "$REVIEW_JSON" | jq -r '.files_to_update[]' 2>/dev/null) | |
| echo "### Verdict: ${STATUS}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ -n "$REASONING" ]; then | |
| echo "**Reasoning:**" >> $GITHUB_STEP_SUMMARY | |
| echo "$REASONING" | while IFS= read -r line; do | |
| echo "- $line" >> $GITHUB_STEP_SUMMARY | |
| done | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ "$STATUS" = "FAIL" ] && [ -n "$FILES" ]; then | |
| echo "**Files to update:**" >> $GITHUB_STEP_SUMMARY | |
| echo "$FILES" | while IFS= read -r f; do | |
| echo "- \`$f\`" >> $GITHUB_STEP_SUMMARY | |
| done | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ "$STATUS" = "PASS" ]; then | |
| echo "Documentation review passed." | |
| elif [ "$STATUS" = "FAIL" ]; then | |
| echo "::error::Documentation review failed — see summary for details" | |
| exit 1 | |
| else | |
| echo "::warning::Unexpected status '${STATUS}' — skipping" | |
| echo "Unexpected AI response status: ${STATUS}" >> $GITHUB_STEP_SUMMARY | |
| fi |