diff --git a/.github/actions/cora-review/action.yml b/.github/actions/cora-review/action.yml index 508891a..c6590f3 100644 --- a/.github/actions/cora-review/action.yml +++ b/.github/actions/cora-review/action.yml @@ -41,7 +41,7 @@ runs: using: 'composite' steps: - name: Fetch LLM secrets from Infisical - uses: Infisical/secrets-action@v1.0.9 + uses: Infisical/secrets-action@8a06c1bdcd5b8635d510c52d4b57a92c1ccef785 # v1.0.9 with: method: 'oidc' identity-id: ${{ inputs.infisical-identity-id }} @@ -52,9 +52,10 @@ runs: - name: Resolve cora-cli version id: resolve shell: bash + env: + INPUT_VERSION: ${{ inputs.cora-version }} run: | - if [ "${{ inputs.cora-version }}" = "latest" ]; then - # Try up to 3 times with delay + if [ "$INPUT_VERSION" = "latest" ]; then for i in 1 2 3; do VERSION=$(curl -sfL --connect-timeout 10 \ https://api.github.com/repos/ajianaz/cora-cli/releases/latest \ @@ -65,19 +66,20 @@ runs: echo "Attempt $i failed, retrying..." sleep 5 done - # Fallback to a known good version if all retries fail if [ -z "$VERSION" ]; then echo "::warning::Failed to resolve latest cora-cli version from GitHub API, using fallback" - VERSION="v0.1.6" + VERSION="v0.1.7" fi else - VERSION="${{ inputs.cora-version }}" + VERSION="$INPUT_VERSION" fi echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT" echo "Resolved cora-cli version: $VERSION" - name: Install cora-cli shell: bash + env: + CORA_VERSION: ${{ steps.resolve.outputs.VERSION }} run: | ARCH=$(uname -m) if [ "$ARCH" = "x86_64" ]; then @@ -88,7 +90,27 @@ runs: echo "Unsupported architecture: $ARCH" exit 1 fi - curl -sL "https://github.com/ajianaz/cora-cli/releases/download/${{ steps.resolve.outputs.VERSION }}/${ASSET}-${{ steps.resolve.outputs.VERSION }}.tar.gz" | tar xz -C /usr/local/bin cora + curl -sL "https://github.com/ajianaz/cora-cli/releases/download/${CORA_VERSION}/${ASSET}-${CORA_VERSION}.tar.gz" \ + -o /tmp/cora.tar.gz + curl -sL "https://github.com/ajianaz/cora-cli/releases/download/${CORA_VERSION}/checksums-sha256.txt" \ + -o /tmp/cora-checksums.txt || true + if [ -f /tmp/cora-checksums.txt ] && [ -s /tmp/cora-checksums.txt ]; then + EXPECTED=$(grep "${ASSET}-${CORA_VERSION}.tar.gz" /tmp/cora-checksums.txt | awk '{print $1}' || true) + ACTUAL=$(sha256sum /tmp/cora.tar.gz | awk '{print $1}') + if [ -n "$EXPECTED" ] && [ "$EXPECTED" != "$ACTUAL" ]; then + echo "::error::Checksum verification failed for ${ASSET}-${CORA_VERSION}.tar.gz" + echo "Expected: $EXPECTED" + echo "Actual: $ACTUAL" + exit 1 + elif [ -z "$EXPECTED" ]; then + echo "::warning::No checksum found for ${ASSET}-${CORA_VERSION}.tar.gz in checksums file" + fi + rm -f /tmp/cora-checksums.txt + else + echo "::warning::No checksums file found, skipping verification" + fi + tar xzf /tmp/cora.tar.gz -C /usr/local/bin cora + rm -f /tmp/cora.tar.gz chmod +x /usr/local/bin/cora cora --version @@ -99,26 +121,31 @@ runs: CORA_API_KEY: ${{ env.CORA_API_KEY }} CORA_BASE_URL: ${{ env.CORA_BASE_URL }} CORA_MODEL: ${{ env.CORA_MODEL }} + INPUT_BASE: ${{ inputs.base-branch }} + INPUT_SEVERITY: ${{ inputs.severity }} run: | cora review \ - --base ${{ inputs.base-branch }} \ + --base "$INPUT_BASE" \ --format sarif \ - --severity ${{ inputs.severity }} \ + --severity "$INPUT_SEVERITY" \ --quiet \ - > cora-results.sarif 2>/dev/null + > cora-results.sarif 2>cora-stderr.log || true echo "Cora review complete ($(wc -c < cora-results.sarif) bytes)" + if [ -s cora-stderr.log ]; then + echo "::warning::Cora stderr: $(cat cora-stderr.log)" + fi - name: Upload SARIF to GitHub Code Scanning if: inputs.upload-sarif == 'true' continue-on-error: true - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@f52b05f4acaaa234e44466e66d29050e135ea9ef # v4.36.0 with: sarif_file: cora-results.sarif category: cora-review - name: Post PR comment if: always() && github.event_name == 'pull_request' - uses: actions/github-script@v7 + uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0 env: GH_TOKEN: ${{ inputs.github-token }} with: @@ -134,7 +161,17 @@ runs: let body; if (!sarifContent || !sarifContent.runs || sarifContent.runs.length === 0) { - body = `## 🔍 Cora AI Code Review\n\n✅ **No issues found.** Code looks good!\n\n---\n_Review powered by [cora-cli](https://github.com/ajianaz/cora-cli) · BYOK · MIT_`; + let fileSize = 0; + try { + fileSize = fs.statSync('cora-results.sarif').size; + } catch (e) { + fileSize = 0; + } + if (fileSize < 10) { + body = `## 🔍 Cora AI Code Review\n\n⚠️ **Review could not complete.** Cora produced an empty result. Check the workflow logs for errors.\n\n---\n_Review powered by [cora-cli](https://github.com/ajianaz/cora-cli) · BYOK · MIT_`; + } else { + body = `## 🔍 Cora AI Code Review\n\n✅ **No issues found.** Code looks good!\n\n---\n_Review powered by [cora-cli](https://github.com/ajianaz/cora-cli) · BYOK · MIT_`; + } } else { const results = sarifContent.runs[0].results || []; if (results.length === 0) { @@ -173,7 +210,6 @@ runs: } } - // Find existing cora comment and update it, or create new const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7595d8..36c0f4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,25 +65,4 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo build --release - cora-review: - name: Cora Review - runs-on: ubuntu-latest - needs: [check, fmt, clippy, test] - if: github.event_name == 'pull_request' - permissions: - contents: read - security-events: write - pull-requests: write - id-token: write - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - - uses: ./.github/actions/cora-review - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - infisical-identity-id: ${{ secrets.INFISICAL_IDENTITY_ID }} diff --git a/.github/workflows/cora-review.yml b/.github/workflows/cora-review.yml new file mode 100644 index 0000000..141a2fe --- /dev/null +++ b/.github/workflows/cora-review.yml @@ -0,0 +1,34 @@ +name: Cora AI Code Review + +on: + pull_request: + branches: [develop] + types: [opened, synchronize, ready_for_review, reopened] + +concurrency: + group: cora-review-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + pull-requests: write + id-token: write + security-events: write + +jobs: + cora-review: + name: Cora Review + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Run Cora AI Code Review + uses: ./.github/actions/cora-review + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + infisical-identity-id: ${{ secrets.INFISICAL_IDENTITY_ID }}