chore: consolidate new foundation and archive v1 (#1495)
This commit is contained in:
+200
@@ -0,0 +1,200 @@
|
||||
#!/bin/bash
|
||||
# common.sh - Shared utilities for Codex review scripts
|
||||
# Source this file from review scripts: source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
|
||||
|
||||
set -e
|
||||
|
||||
CODEX_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
GIT_SCRIPT_DIR="$CODEX_SCRIPT_DIR/../git"
|
||||
|
||||
# Source platform detection
|
||||
source "$GIT_SCRIPT_DIR/detect-platform.sh"
|
||||
|
||||
# Check codex is installed
|
||||
check_codex() {
|
||||
if ! command -v codex &>/dev/null; then
|
||||
echo "Error: codex CLI not found. Install with: npm i -g @openai/codex" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check jq is installed (needed for JSON processing)
|
||||
check_jq() {
|
||||
if ! command -v jq &>/dev/null; then
|
||||
echo "Error: jq not found. Install with your package manager." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Build the codex exec command args for the review mode
|
||||
# Arguments: $1=mode (--uncommitted|--base|--commit), $2=value (branch/sha)
|
||||
build_diff_context() {
|
||||
local mode="$1"
|
||||
local value="$2"
|
||||
local diff_text=""
|
||||
|
||||
case "$mode" in
|
||||
uncommitted)
|
||||
diff_text=$(git diff HEAD 2>/dev/null; git diff --cached 2>/dev/null; git ls-files --others --exclude-standard 2>/dev/null | while read -r f; do echo "=== NEW FILE: $f ==="; cat "$f" 2>/dev/null; done)
|
||||
;;
|
||||
base)
|
||||
diff_text=$(git diff "${value}...HEAD" 2>/dev/null)
|
||||
;;
|
||||
commit)
|
||||
diff_text=$(git show "$value" 2>/dev/null)
|
||||
;;
|
||||
pr)
|
||||
# Provider detection writes its result to stdout; suppress it so it cannot
|
||||
# be mistaken for diff content when this function is used in a substitution.
|
||||
detect_platform >/dev/null
|
||||
if [[ "$PLATFORM" == "github" ]]; then
|
||||
diff_text=$(gh pr diff "$value" 2>/dev/null) || {
|
||||
echo "Error: Failed to fetch the diff for PR #${value}." >&2
|
||||
return 1
|
||||
}
|
||||
elif [[ "$PLATFORM" == "gitea" ]]; then
|
||||
local pr_base base_ref pr_head_ref
|
||||
pr_base=$(tea pr list --fields index,base --output simple 2>/dev/null | awk -v pr="$value" '$1 == pr { print $2; exit }')
|
||||
if [[ -z "$pr_base" ]]; then
|
||||
echo "Error: Could not resolve the base branch for Gitea PR #${value}." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
base_ref="refs/remotes/origin/${pr_base}"
|
||||
pr_head_ref="refs/remotes/origin/pr/${value}/head"
|
||||
if ! git fetch --quiet origin \
|
||||
"+refs/heads/${pr_base}:${base_ref}" \
|
||||
"+refs/pull/${value}/head:${pr_head_ref}"; then
|
||||
echo "Error: Failed to fetch the base and head refs for Gitea PR #${value}." >&2
|
||||
return 1
|
||||
fi
|
||||
diff_text=$(git diff "${base_ref}...${pr_head_ref}") || {
|
||||
echo "Error: Failed to diff the fetched refs for Gitea PR #${value}." >&2
|
||||
return 1
|
||||
}
|
||||
else
|
||||
echo "Error: Unsupported git platform while resolving PR #${value}." >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$mode" == "pr" && -z "${diff_text//[[:space:]]/}" ]]; then
|
||||
echo "Error: Unable to construct a non-empty diff for PR #${value}; verify the PR refs and provider access." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf '%s\n' "$diff_text"
|
||||
}
|
||||
|
||||
# Format JSON findings as markdown for PR comments
|
||||
# Arguments: $1=json_file, $2=review_type (code|security)
|
||||
format_findings_as_markdown() {
|
||||
local json_file="$1"
|
||||
local review_type="$2"
|
||||
|
||||
if [[ ! -f "$json_file" ]]; then
|
||||
echo "Error: JSON file not found: $json_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local summary verdict confidence
|
||||
summary=$(jq -r '.summary' "$json_file")
|
||||
confidence=$(jq -r '.confidence' "$json_file")
|
||||
|
||||
if [[ "$review_type" == "code" ]]; then
|
||||
verdict=$(jq -r '.verdict' "$json_file")
|
||||
local blockers should_fix suggestions files_reviewed
|
||||
blockers=$(jq -r '.stats.blockers' "$json_file")
|
||||
should_fix=$(jq -r '.stats.should_fix' "$json_file")
|
||||
suggestions=$(jq -r '.stats.suggestions' "$json_file")
|
||||
files_reviewed=$(jq -r '.stats.files_reviewed' "$json_file")
|
||||
|
||||
cat <<EOF
|
||||
## Codex Code Review
|
||||
|
||||
**Verdict:** ${verdict} | **Confidence:** ${confidence} | **Files reviewed:** ${files_reviewed}
|
||||
**Findings:** ${blockers} blockers, ${should_fix} should-fix, ${suggestions} suggestions
|
||||
|
||||
### Summary
|
||||
${summary}
|
||||
|
||||
EOF
|
||||
else
|
||||
local risk_level critical high medium low files_reviewed
|
||||
risk_level=$(jq -r '.risk_level' "$json_file")
|
||||
critical=$(jq -r '.stats.critical' "$json_file")
|
||||
high=$(jq -r '.stats.high' "$json_file")
|
||||
medium=$(jq -r '.stats.medium' "$json_file")
|
||||
low=$(jq -r '.stats.low' "$json_file")
|
||||
files_reviewed=$(jq -r '.stats.files_reviewed' "$json_file")
|
||||
|
||||
cat <<EOF
|
||||
## Codex Security Review
|
||||
|
||||
**Risk Level:** ${risk_level} | **Confidence:** ${confidence} | **Files reviewed:** ${files_reviewed}
|
||||
**Findings:** ${critical} critical, ${high} high, ${medium} medium, ${low} low
|
||||
|
||||
### Summary
|
||||
${summary}
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Output findings
|
||||
local finding_count
|
||||
finding_count=$(jq '.findings | length' "$json_file")
|
||||
|
||||
if [[ "$finding_count" -gt 0 ]]; then
|
||||
echo "### Findings"
|
||||
echo ""
|
||||
|
||||
jq -r '.findings[] | "#### [\(.severity | ascii_upcase)] \(.title)\n- **File:** `\(.file)`\(if .line_start then " (L\(.line_start)\(if .line_end and .line_end != .line_start then "-L\(.line_end)" else "" end))" else "" end)\n- \(.description)\(if .suggestion then "\n- **Suggestion:** \(.suggestion)" else "" end)\(if .cwe_id then "\n- **CWE:** \(.cwe_id)" else "" end)\(if .owasp_category then "\n- **OWASP:** \(.owasp_category)" else "" end)\(if .remediation then "\n- **Remediation:** \(.remediation)" else "" end)\n"' "$json_file"
|
||||
else
|
||||
echo "*No issues found.*"
|
||||
fi
|
||||
|
||||
echo "---"
|
||||
echo "*Reviewed by Codex ($(codex --version 2>/dev/null || echo "unknown"))*"
|
||||
}
|
||||
|
||||
# Post review findings to a PR
|
||||
# Arguments: $1=pr_number, $2=json_file, $3=review_type (code|security)
|
||||
post_to_pr() {
|
||||
local pr_number="$1"
|
||||
local json_file="$2"
|
||||
local review_type="$3"
|
||||
|
||||
local markdown
|
||||
markdown=$(format_findings_as_markdown "$json_file" "$review_type")
|
||||
|
||||
detect_platform
|
||||
|
||||
# Determine review action based on findings
|
||||
local action="comment"
|
||||
if [[ "$review_type" == "code" ]]; then
|
||||
local verdict
|
||||
verdict=$(jq -r '.verdict' "$json_file")
|
||||
action="$verdict"
|
||||
else
|
||||
local risk_level
|
||||
risk_level=$(jq -r '.risk_level' "$json_file")
|
||||
case "$risk_level" in
|
||||
critical|high) action="request-changes" ;;
|
||||
medium) action="comment" ;;
|
||||
low|none) action="comment" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Post the review
|
||||
"$GIT_SCRIPT_DIR/pr-review.sh" -n "$pr_number" -a "$action" -c "$markdown"
|
||||
}
|
||||
|
||||
# Print review results to stdout
|
||||
# Arguments: $1=json_file, $2=review_type (code|security)
|
||||
print_results() {
|
||||
local json_file="$1"
|
||||
local review_type="$2"
|
||||
|
||||
format_findings_as_markdown "$json_file" "$review_type"
|
||||
}
|
||||
Reference in New Issue
Block a user