Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c5de091
fix(ci): add --allow-dirty to cargo publish (Cargo.lock mismatch on t…
May 30, 2026
fe06cc2
feat: add missing CLI flags + fix all documentation
May 30, 2026
38522e9
fix: resolve clippy format_in_format_args + cargo fmt
May 30, 2026
99b6447
feat(ci): add cora AI review job to CI pipeline
May 30, 2026
dc48856
fix: SARIF schema compliance for GitHub Code Scanning
May 30, 2026
e360973
fix(ci): address cora self-review findings
May 30, 2026
e1929c3
refactor(ci): extract cora review into composite action
May 30, 2026
9df9289
fix(ci): remove || true and cargo build stderr suppress
May 30, 2026
9bb99e8
perf: remove unused deps + replace deprecated serde_yaml
May 30, 2026
f81c65f
fix: replace serde_yml (deprecated) with serde_yaml_ng
May 30, 2026
ff6e385
fix(ci): normalize release binary naming + sync action (#51)
ajianaz May 31, 2026
d21f8bd
chore: bump version to v0.1.2 (#52)
ajianaz May 31, 2026
c072f84
docs: add CI setup guide, cora-review-simple action, website link
May 31, 2026
6287683
docs: use cora.ajianaz.dev as website link
May 31, 2026
17f0a8c
fix: OG tags use cora.ajianaz.dev instead of .com
May 31, 2026
a0e58fc
feat: add OG image + fix OG tags domain (#56)
ajianaz May 31, 2026
4af6fbd
docs: fix all documentation issues — schema, flags, URLs, env vars, s…
ajianaz May 31, 2026
dab176f
docs: add CHANGELOG.md with v0.1.0–v0.1.2 history
May 31, 2026
c66aee1
feat: config redesign + severity comparison fix
May 31, 2026
6a5baff
style: cargo fmt
May 31, 2026
fe1fff3
docs: update README, CONTRIBUTING, CHANGELOG for config redesign + se…
May 31, 2026
b64d401
fix: address cora self-review findings (#60)
May 31, 2026
d51983f
chore: trigger CI
May 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions .github/actions/cora-review-simple/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
name: 'Cora AI Code Review'
description: 'Run cora AI code review on a PR diff — posts a PR comment. Uses GitHub Secrets directly (no Infisical required). SARIF upload is optional.'

inputs:
base-branch:
description: 'Base branch to compare against (default: origin/develop)'
required: false
default: 'origin/develop'
severity:
description: 'Minimum severity to report (info, minor, major, critical)'
required: false
default: 'major'
cora-version:
description: 'cora-cli version tag (default: latest release)'
required: false
default: 'latest'
upload-sarif:
description: 'Upload SARIF to GitHub Code Scanning (default: false)'
required: false
default: 'false'
cora-api-key:
description: 'LLM API key (from secrets.CORA_API_KEY)'
required: true
cora-base-url:
description: 'LLM API base URL (from secrets.CORA_BASE_URL)'
required: true
cora-model:
description: 'LLM model ID (from secrets.CORA_MODEL)'
required: true
github-token:
description: 'GitHub token for PR comments and SARIF upload'
required: true

runs:
using: 'composite'
steps:
- name: Resolve cora-cli version
id: resolve
shell: bash
run: |
if [ "${{ inputs.cora-version }}" = "latest" ]; then
VERSION=$(curl -sL https://api.github.com/repos/ajianaz/cora-cli/releases/latest | python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])")
else
VERSION="${{ inputs.cora-version }}"
fi
echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
echo "Resolved cora-cli version: $VERSION"

- name: Install cora-cli
shell: bash
run: |
ARCH=$(uname -m)
if [ "$ARCH" = "x86_64" ]; then
ASSET="cora-x86_64-unknown-linux-gnu"
elif [ "$ARCH" = "aarch64" ]; then
ASSET="cora-aarch64-unknown-linux-gnu"
else
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
chmod +x /usr/local/bin/cora
cora --version

- name: Run cora review
id: review
shell: bash
env:
CORA_API_KEY: ${{ inputs.cora-api-key }}
CORA_BASE_URL: ${{ inputs.cora-base-url }}
CORA_MODEL: ${{ inputs.cora-model }}
run: |
cora review \
--base ${{ inputs.base-branch }} \
--format sarif \
--severity ${{ inputs.severity }} \
--quiet \
> cora-results.sarif 2>/dev/null
echo "Cora review complete ($(wc -c < cora-results.sarif) bytes)"

- name: Upload SARIF to GitHub Code Scanning
if: inputs.upload-sarif == 'true'
continue-on-error: true
uses: github/codeql-action/upload-sarif@v4
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
env:
GH_TOKEN: ${{ inputs.github-token }}
with:
script: |
const fs = require('fs');

let sarifContent;
try {
sarifContent = JSON.parse(fs.readFileSync('cora-results.sarif', 'utf8'));
} catch (e) {
sarifContent = null;
}

let body;
if (!sarifContent || !sarifContent.runs || sarifContent.runs.length === 0) {
body = `## 🔍 Cora AI Code Review\n\n✅ **No issues found.** Code looks good!`;
} else {
const results = sarifContent.runs[0].results || [];
if (results.length === 0) {
body = `## 🔍 Cora AI Code Review\n\n✅ **No issues found.** Code looks good!`;
} else {
const grouped = {};
for (const r of results) {
const sev = (r.level || 'note').charAt(0).toUpperCase() + (r.level || 'note').slice(1);
if (!grouped[sev]) grouped[sev] = [];
grouped[sev].push(r);
}

const severityOrder = ['Error', 'Warning', 'Note'];
let table = '';

for (const sev of severityOrder) {
if (!grouped[sev]) continue;
const icon = sev === 'Error' ? '🔴' : sev === 'Warning' ? '🟡' : '🔵';
table += `\n### ${icon} ${sev} (${grouped[sev].length})\n\n`;
for (const r of grouped[sev]) {
const loc = r.locations?.[0]?.physicalLocation;
const file = loc?.artifactLocation?.uri || 'unknown';
const line = loc?.region?.startLine || '?';
const msg = r.message?.text || r.message?.markdown || 'No message';
table += `- \`${file}:${line}\` — ${msg}\n`;
}
}

const hasErrors = (grouped['Error'] || []).length > 0;
const hasWarnings = (grouped['Warning'] || []).length > 0;
const status = hasErrors ? '❌ **Blocked** — critical issues found.' :
hasWarnings ? '⚠️ **Review recommended** — warnings found.' :
'✅ **Passed** — only informational notes.';

body = `## 🔍 Cora AI Code Review\n\n${status}\n${table}\n---\n_Review powered by [cora-cli](https://github.com/ajianaz/cora-cli) · BYOK · MIT_`;
}
}

// 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,
issue_number: context.issue.number,
});

const existing = comments.find(c =>
c.user.login === 'github-actions[bot]' &&
c.body.startsWith('## 🔍 Cora AI Code Review')
);

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}

- name: Check for blocking issues
if: always()
shell: bash
run: |
if [ -f cora-results.sarif ]; then
ERRORS=$(python3 -c "
import json, sys
try:
data = json.load(open('cora-results.sarif'))
results = data.get('runs', [{}])[0].get('results', [])
errors = [r for r in results if r.get('level') == 'error']
print(len(errors))
except:
print(0)
" 2>/dev/null || echo "0")

if [ "$ERRORS" -gt 0 ]; then
echo "::error::Cora found $ERRORS blocking issue(s)."
exit 1
fi
fi
echo "No blocking issues."
Loading