Merge pull request 'update/image-build-workflow' (#7) from update/image-build-workflow into dev
All checks were successful
docker / lint (push) Successful in 22s
docker / test (push) Successful in 18s
lint / lint (push) Successful in 24s
test / test (push) Successful in 19s
docker / docker-test (push) Successful in 8s
docker / docker-publish (push) Successful in 7s
docker / lint (pull_request) Successful in 1m31s
docker / test (pull_request) Successful in 18s
lint / lint (pull_request) Successful in 24s
test / test (pull_request) Successful in 20s
docker / docker-test (pull_request) Successful in 38s
docker / docker-publish (pull_request) Has been skipped
All checks were successful
docker / lint (push) Successful in 22s
docker / test (push) Successful in 18s
lint / lint (push) Successful in 24s
test / test (push) Successful in 19s
docker / docker-test (push) Successful in 8s
docker / docker-publish (push) Successful in 7s
docker / lint (pull_request) Successful in 1m31s
docker / test (pull_request) Successful in 18s
lint / lint (pull_request) Successful in 24s
test / test (pull_request) Successful in 20s
docker / docker-test (pull_request) Successful in 38s
docker / docker-publish (pull_request) Has been skipped
Reviewed-on: #7
This commit was merged in pull request #7.
This commit is contained in:
61
.gitea/workflows/ai-chat.yml
Normal file
61
.gitea/workflows/ai-chat.yml
Normal file
@@ -0,0 +1,61 @@
|
||||
name: AI Chat ({{BOT_USERNAME}})
|
||||
|
||||
# WORKFLOW ROUTING:
|
||||
# This workflow handles FREE-FORM questions/chat (no specific command)
|
||||
# Other workflows: ai-issue-triage.yml (@{{BOT_NAME}} triage), ai-comment-reply.yml (specific commands)
|
||||
# This is the FALLBACK for any @{{BOT_NAME}} mention that isn't a known command
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
# CUSTOMIZE YOUR BOT NAME:
|
||||
# Change '@{{BOT_NAME}}' in all conditions below to match your config.yml mention_prefix
|
||||
# Examples: '@bartender', '@uni', '@joey', '@codebot'
|
||||
|
||||
jobs:
|
||||
ai-chat:
|
||||
# Only run if comment mentions the bot but NOT a specific command
|
||||
# This prevents duplicate runs with ai-comment-reply.yml and ai-issue-triage.yml
|
||||
# CRITICAL: Ignore bot's own comments to prevent infinite loops (bot username: {{BOT_USERNAME}})
|
||||
if: |
|
||||
{{PLATFORM}}.event.comment.user.login != '{{BOT_USERNAME}}' &&
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}}') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} triage') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} help') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} explain') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} suggest') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} security') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} summarize') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} changelog') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} explain-diff') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} review-again') &&
|
||||
!contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} setup-labels')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: {{OPENRABBIT_REPO}}
|
||||
path: .ai-review
|
||||
token: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- run: pip install requests pyyaml
|
||||
|
||||
- name: Run AI Chat
|
||||
env:
|
||||
AI_REVIEW_TOKEN: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
AI_REVIEW_REPO: ${{ {{PLATFORM}}.repository }}
|
||||
AI_REVIEW_API_URL: {{API_URL}}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
||||
OLLAMA_HOST: ${{ secrets.OLLAMA_HOST }}
|
||||
SEARXNG_URL: ${{ secrets.SEARXNG_URL }}
|
||||
run: |
|
||||
cd .ai-review/tools/ai-review
|
||||
python main.py comment ${{ {{PLATFORM}}.repository }} ${{ {{PLATFORM}}.event.issue.number }} "${{ {{PLATFORM}}.event.comment.body }}"
|
||||
58
.gitea/workflows/ai-codebase-review.yml
Normal file
58
.gitea/workflows/ai-codebase-review.yml
Normal file
@@ -0,0 +1,58 @@
|
||||
name: AI Codebase Quality Review
|
||||
|
||||
on:
|
||||
# Weekly scheduled run
|
||||
# schedule:
|
||||
# - cron: "0 0 * * 0" # Every Sunday at midnight
|
||||
|
||||
# Manual trigger
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
report_type:
|
||||
description: "Type of report to generate"
|
||||
required: false
|
||||
default: "full"
|
||||
type: choice
|
||||
options:
|
||||
- full
|
||||
- security
|
||||
- quick
|
||||
|
||||
jobs:
|
||||
ai-codebase-review:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Checkout the repository
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Full history for analysis
|
||||
|
||||
# Checkout central AI tooling
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: { { OPENRABBIT_REPO } }
|
||||
path: .ai-review
|
||||
token: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
|
||||
# Setup Python
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
# Install dependencies
|
||||
- run: pip install requests pyyaml
|
||||
|
||||
# Run AI codebase analysis
|
||||
- name: Run AI Codebase Analysis
|
||||
env:
|
||||
AI_REVIEW_TOKEN: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
AI_REVIEW_REPO: ${{ {{PLATFORM}}.repository }}
|
||||
AI_REVIEW_API_URL: { { API_URL } }
|
||||
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
||||
OLLAMA_HOST: ${{ secrets.OLLAMA_HOST }}
|
||||
run: |
|
||||
cd .ai-review/tools/ai-review
|
||||
python main.py codebase ${{ {{PLATFORM}}.repository }}
|
||||
98
.gitea/workflows/ai-comment-reply.yml
Normal file
98
.gitea/workflows/ai-comment-reply.yml
Normal file
@@ -0,0 +1,98 @@
|
||||
name: AI Comment Reply
|
||||
|
||||
# WORKFLOW ROUTING:
|
||||
# This workflow handles SPECIFIC commands: help, explain, suggest, security, summarize, changelog, explain-diff, review-again, setup-labels
|
||||
# Other workflows: ai-issue-triage.yml (@{{BOT_NAME}} triage), ai-chat.yml (free-form questions)
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
# CUSTOMIZE YOUR BOT NAME:
|
||||
# Change '@{{BOT_NAME}}' in the 'if' condition below to match your config.yml mention_prefix
|
||||
# Examples: '@bartender', '@uni', '@joey', '@codebot'
|
||||
|
||||
jobs:
|
||||
ai-reply:
|
||||
runs-on: ubuntu-latest
|
||||
# Only run for specific commands (not free-form chat or triage)
|
||||
# This prevents duplicate runs with ai-chat.yml and ai-issue-triage.yml
|
||||
# CRITICAL: Ignore bot's own comments to prevent infinite loops (bot username: {{BOT_USERNAME}})
|
||||
if: |
|
||||
{{PLATFORM}}.event.comment.user.login != '{{BOT_USERNAME}}' &&
|
||||
(contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} help') ||
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} explain') ||
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} suggest') ||
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} security') ||
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} summarize') ||
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} changelog') ||
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} explain-diff') ||
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} review-again') ||
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} setup-labels'))
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: {{OPENRABBIT_REPO}}
|
||||
path: .ai-review
|
||||
token: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- run: pip install requests pyyaml
|
||||
|
||||
- name: Run AI Comment Response
|
||||
env:
|
||||
AI_REVIEW_TOKEN: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
AI_REVIEW_API_URL: {{API_URL}}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
||||
OLLAMA_HOST: ${{ secrets.OLLAMA_HOST }}
|
||||
run: |
|
||||
cd .ai-review/tools/ai-review
|
||||
|
||||
# Determine if this is a PR or issue comment
|
||||
IS_PR="${{ {{PLATFORM}}.event.issue.pull_request != null }}"
|
||||
REPO="${{ {{PLATFORM}}.repository }}"
|
||||
ISSUE_NUMBER="${{ {{PLATFORM}}.event.issue.number }}"
|
||||
|
||||
# Validate inputs
|
||||
if [ -z "$REPO" ] || [ -z "$ISSUE_NUMBER" ]; then
|
||||
echo "Error: Missing required parameters"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate repository format (owner/repo)
|
||||
if ! echo "$REPO" | grep -qE '^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$'; then
|
||||
echo "Error: Invalid repository format: $REPO"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$IS_PR" = "true" ]; then
|
||||
# This is a PR comment - use safe dispatch with minimal event data
|
||||
# Build minimal event payload (does not include sensitive user data)
|
||||
EVENT_DATA=$(cat <<EOF
|
||||
{
|
||||
"action": "created",
|
||||
"issue": {
|
||||
"number": ${{ {{PLATFORM}}.event.issue.number }},
|
||||
"pull_request": {}
|
||||
},
|
||||
"comment": {
|
||||
"id": ${{ {{PLATFORM}}.event.comment.id }},
|
||||
"body": $(echo '${{ {{PLATFORM}}.event.comment.body }}' | jq -Rs .)
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# Use safe dispatch utility
|
||||
python utils/safe_dispatch.py issue_comment "$REPO" "$EVENT_DATA"
|
||||
else
|
||||
# This is an issue comment - use the comment command
|
||||
COMMENT_BODY='${{ {{PLATFORM}}.event.comment.body }}'
|
||||
python main.py comment "$REPO" "$ISSUE_NUMBER" "$COMMENT_BODY"
|
||||
fi
|
||||
44
.gitea/workflows/ai-issue-triage.yml
Normal file
44
.gitea/workflows/ai-issue-triage.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
name: AI Issue Triage
|
||||
|
||||
# WORKFLOW ROUTING:
|
||||
# This workflow handles ONLY the 'triage' command
|
||||
# Other workflows: ai-comment-reply.yml (specific commands), ai-chat.yml (free-form questions)
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
ai-triage:
|
||||
runs-on: ubuntu-latest
|
||||
# Only run if comment contains @{{BOT_NAME}} triage
|
||||
# CRITICAL: Ignore bot's own comments to prevent infinite loops (bot username: {{BOT_USERNAME}})
|
||||
if: |
|
||||
{{PLATFORM}}.event.comment.user.login != '{{BOT_USERNAME}}' &&
|
||||
contains({{PLATFORM}}.event.comment.body, '@{{BOT_NAME}} triage')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: {{OPENRABBIT_REPO}}
|
||||
path: .ai-review
|
||||
token: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- run: pip install requests pyyaml
|
||||
|
||||
- name: Run AI Issue Triage
|
||||
env:
|
||||
AI_REVIEW_TOKEN: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
AI_REVIEW_REPO: ${{ {{PLATFORM}}.repository }}
|
||||
AI_REVIEW_API_URL: {{API_URL}}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
||||
OLLAMA_HOST: ${{ secrets.OLLAMA_HOST }}
|
||||
run: |
|
||||
cd .ai-review/tools/ai-review
|
||||
python main.py issue ${{ {{PLATFORM}}.repository }} ${{ {{PLATFORM}}.event.issue.number }}
|
||||
@@ -2,10 +2,20 @@ name: docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
pull_request_review:
|
||||
types:
|
||||
- submitted
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
if: ${{ github.event_name != 'pull_request_review' || github.event.review.state == 'approved' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -13,7 +23,7 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
python-version: "3.12"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
@@ -26,6 +36,7 @@ jobs:
|
||||
mypy src
|
||||
|
||||
test:
|
||||
if: ${{ github.event_name != 'pull_request_review' || github.event.review.state == 'approved' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -33,7 +44,7 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
python-version: "3.12"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
@@ -41,7 +52,8 @@ jobs:
|
||||
- name: Run tests
|
||||
run: pytest --cov=aegis_gitea_mcp --cov-report=term-missing --cov-fail-under=80
|
||||
|
||||
docker-build:
|
||||
docker-test:
|
||||
if: ${{ github.event_name != 'pull_request_review' || github.event.review.state == 'approved' }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, test]
|
||||
env:
|
||||
@@ -50,25 +62,96 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build image tagged with commit SHA
|
||||
- name: Build candidate image
|
||||
run: |
|
||||
SHA_TAG="${GITHUB_SHA:-${CI_COMMIT_SHA:-local}}"
|
||||
docker build -f docker/Dockerfile -t ${IMAGE_NAME}:${SHA_TAG} .
|
||||
|
||||
- name: Tag latest on main
|
||||
- name: Smoke-test image
|
||||
run: |
|
||||
REF_NAME="${GITHUB_REF_NAME:-${CI_COMMIT_REF_NAME:-}}"
|
||||
SHA_TAG="${GITHUB_SHA:-${CI_COMMIT_SHA:-local}}"
|
||||
if [ "${REF_NAME}" = "main" ]; then
|
||||
docker tag ${IMAGE_NAME}:${SHA_TAG} ${IMAGE_NAME}:latest
|
||||
docker run --rm --entrypoint python ${IMAGE_NAME}:${SHA_TAG} -c "import aegis_gitea_mcp"
|
||||
|
||||
docker-publish:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, test, docker-test]
|
||||
if: >-
|
||||
(github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'dev')) ||
|
||||
(github.event_name == 'pull_request_review' &&
|
||||
github.event.review.state == 'approved' &&
|
||||
(github.event.pull_request.base.ref == 'main' || github.event.pull_request.base.ref == 'dev'))
|
||||
env:
|
||||
IMAGE_NAME: aegis-gitea-mcp
|
||||
REGISTRY_IMAGE: ${{ vars.REGISTRY_IMAGE }}
|
||||
REGISTRY_HOST: ${{ vars.REGISTRY_HOST }}
|
||||
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
|
||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Resolve tags
|
||||
id: tags
|
||||
run: |
|
||||
EVENT_NAME="${GITHUB_EVENT_NAME:-${CI_EVENT_NAME:-}}"
|
||||
REF_NAME="${GITHUB_REF_NAME:-${CI_COMMIT_REF_NAME:-}}"
|
||||
BASE_REF="${PR_BASE_REF:-${GITHUB_BASE_REF:-${CI_BASE_REF:-}}}"
|
||||
SHA_TAG="${GITHUB_SHA:-${CI_COMMIT_SHA:-local}}"
|
||||
|
||||
if [ "${EVENT_NAME}" = "pull_request_review" ]; then
|
||||
TARGET_BRANCH="${BASE_REF}"
|
||||
SHA_TAG="${PR_HEAD_SHA:-$SHA_TAG}"
|
||||
else
|
||||
TARGET_BRANCH="${REF_NAME}"
|
||||
fi
|
||||
|
||||
if [ "${TARGET_BRANCH}" = "main" ]; then
|
||||
STABLE_TAG="latest"
|
||||
elif [ "${TARGET_BRANCH}" = "dev" ]; then
|
||||
STABLE_TAG="dev"
|
||||
else
|
||||
echo "Unsupported target branch '${TARGET_BRANCH}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "sha_tag=${SHA_TAG}" >> "${GITHUB_OUTPUT}"
|
||||
echo "stable_tag=${STABLE_TAG}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Build releasable image
|
||||
id: image
|
||||
run: |
|
||||
IMAGE_REF="${REGISTRY_IMAGE:-${IMAGE_NAME}}"
|
||||
echo "image_ref=${IMAGE_REF}" >> "${GITHUB_OUTPUT}"
|
||||
docker build -f docker/Dockerfile -t ${IMAGE_REF}:${{ steps.tags.outputs.sha_tag }} .
|
||||
docker tag ${IMAGE_REF}:${{ steps.tags.outputs.sha_tag }} ${IMAGE_REF}:${{ steps.tags.outputs.stable_tag }}
|
||||
|
||||
- name: Login to registry
|
||||
if: ${{ vars.PUSH_IMAGE == 'true' }}
|
||||
run: |
|
||||
if [ -z "${REGISTRY_USER}" ] || [ -z "${REGISTRY_TOKEN}" ]; then
|
||||
echo "REGISTRY_USER and REGISTRY_TOKEN secrets are required when PUSH_IMAGE=true"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IMAGE_REF="${{ steps.image.outputs.image_ref }}"
|
||||
LOGIN_HOST="${REGISTRY_HOST}"
|
||||
if [ -z "${LOGIN_HOST}" ]; then
|
||||
FIRST_PART="${IMAGE_REF%%/*}"
|
||||
case "${FIRST_PART}" in
|
||||
*.*|*:*|localhost) LOGIN_HOST="${FIRST_PART}" ;;
|
||||
*) LOGIN_HOST="docker.io" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
printf "%s" "${REGISTRY_TOKEN}" | docker login "${LOGIN_HOST}" --username "${REGISTRY_USER}" --password-stdin
|
||||
|
||||
- name: Optional registry push
|
||||
if: ${{ vars.PUSH_IMAGE == 'true' }}
|
||||
run: |
|
||||
SHA_TAG="${GITHUB_SHA:-${CI_COMMIT_SHA:-local}}"
|
||||
docker push ${IMAGE_NAME}:${SHA_TAG}
|
||||
REF_NAME="${GITHUB_REF_NAME:-${CI_COMMIT_REF_NAME:-}}"
|
||||
if [ "${REF_NAME}" = "main" ]; then
|
||||
docker push ${IMAGE_NAME}:latest
|
||||
fi
|
||||
IMAGE_REF="${{ steps.image.outputs.image_ref }}"
|
||||
docker push ${IMAGE_REF}:${{ steps.tags.outputs.sha_tag }}
|
||||
docker push ${IMAGE_REF}:${{ steps.tags.outputs.stable_tag }}
|
||||
|
||||
53
.gitea/workflows/enterprise-ai-review.yml
Normal file
53
.gitea/workflows/enterprise-ai-review.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
name: Enterprise AI Code Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
jobs:
|
||||
ai-review:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Checkout the PR repository
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Checkout the CENTRAL AI tooling repo
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: {{OPENRABBIT_REPO}}
|
||||
path: .ai-review
|
||||
token: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
|
||||
# Setup Python
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
# Install dependencies
|
||||
- run: pip install requests pyyaml
|
||||
|
||||
# Run the AI review
|
||||
- name: Run Enterprise AI Review
|
||||
env:
|
||||
AI_REVIEW_TOKEN: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||
AI_REVIEW_REPO: ${{ {{PLATFORM}}.repository }}
|
||||
AI_REVIEW_API_URL: {{API_URL}}
|
||||
AI_REVIEW_PR_NUMBER: ${{ {{PLATFORM}}.event.pull_request.number }}
|
||||
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
||||
OLLAMA_HOST: ${{ secrets.OLLAMA_HOST }}
|
||||
run: |
|
||||
cd .ai-review/tools/ai-review
|
||||
python main.py pr ${{ {{PLATFORM}}.repository }} ${{ {{PLATFORM}}.event.pull_request.number }} \
|
||||
--title "${{ {{PLATFORM}}.event.pull_request.title }}"
|
||||
|
||||
# Fail CI on HIGH severity (optional)
|
||||
- name: Check Review Result
|
||||
if: failure()
|
||||
run: |
|
||||
echo "AI Review found HIGH severity issues. Please address them before merging."
|
||||
exit 1
|
||||
@@ -39,7 +39,13 @@ Workflows live in `.gitea/workflows/`:
|
||||
|
||||
- `lint.yml`: ruff + format checks + mypy.
|
||||
- `test.yml`: lint + tests + coverage fail-under `80`.
|
||||
- `docker.yml`: gated Docker build (depends on lint+test), SHA tag, `latest` on `main`.
|
||||
- `docker.yml`: lint + test + docker smoke-test gating; image publish on push to `main`/`dev` and on approved PR review targeting `main`/`dev`; tags include commit SHA plus `latest` (`main`) or `dev` (`dev`).
|
||||
|
||||
Docker publish settings:
|
||||
- `vars.PUSH_IMAGE=true` enables registry push.
|
||||
- `vars.REGISTRY_IMAGE` sets the target image name (for example `registry.example.com/org/aegis-gitea-mcp`).
|
||||
- `vars.REGISTRY_HOST` is optional and overrides the login host detection.
|
||||
- `secrets.REGISTRY_USER` and `secrets.REGISTRY_TOKEN` are required when push is enabled.
|
||||
|
||||
## Production Recommendations
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class MetricsRegistry:
|
||||
lines.append("# TYPE aegis_tool_calls_total counter")
|
||||
for (tool_name, status), count in sorted(self._tool_calls_total.items()):
|
||||
lines.append(
|
||||
"aegis_tool_calls_total" f'{{tool="{tool_name}",status="{status}"}} {count}'
|
||||
f'aegis_tool_calls_total{{tool="{tool_name}",status="{status}"}} {count}'
|
||||
)
|
||||
|
||||
lines.append(
|
||||
|
||||
@@ -371,6 +371,24 @@ async def authenticate_and_rate_limit(
|
||||
"scopes_observed": observed_scopes,
|
||||
},
|
||||
)
|
||||
message = (
|
||||
"OAuth token is valid but lacks required Gitea API access. "
|
||||
"Re-authorize this OAuth app in Gitea and try again."
|
||||
)
|
||||
if request.url.path.startswith("/mcp/"):
|
||||
return _oauth_unauthorized_response(
|
||||
request,
|
||||
message,
|
||||
scope=READ_SCOPE,
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=401,
|
||||
content={
|
||||
"error": "Authentication failed",
|
||||
"message": message,
|
||||
"request_id": getattr(request.state, "request_id", "-"),
|
||||
},
|
||||
)
|
||||
else:
|
||||
probe_result = "pass"
|
||||
_api_scope_cache[token_hash] = now + _API_SCOPE_CACHE_TTL
|
||||
|
||||
@@ -34,6 +34,10 @@ def _set_base_env(
|
||||
monkeypatch.setenv("POLICY_FILE_PATH", str(policy_path))
|
||||
|
||||
|
||||
def _yaml_with_trailing_newline(content: str) -> str:
|
||||
return content.strip() + "\n"
|
||||
|
||||
|
||||
def test_automation_job_denied_when_disabled(
|
||||
monkeypatch: pytest.MonkeyPatch, tmp_path: Path, allow_oauth: None
|
||||
) -> None:
|
||||
@@ -61,7 +65,7 @@ def test_automation_job_executes_when_enabled(
|
||||
"""Dependency scan job should execute when automation is enabled and policy allows it."""
|
||||
policy_path = tmp_path / "policy.yaml"
|
||||
policy_path.write_text(
|
||||
"""
|
||||
_yaml_with_trailing_newline("""
|
||||
defaults:
|
||||
read: allow
|
||||
write: deny
|
||||
@@ -69,7 +73,7 @@ tools:
|
||||
allow:
|
||||
- automation_dependency_hygiene_scan
|
||||
- automation_webhook_ingest
|
||||
""".strip() + "\n",
|
||||
"""),
|
||||
encoding="utf-8",
|
||||
)
|
||||
_set_base_env(monkeypatch, automation_enabled=True, policy_path=policy_path)
|
||||
@@ -95,14 +99,14 @@ def test_automation_webhook_policy_denied(
|
||||
"""Webhook ingestion must respect policy deny rules."""
|
||||
policy_path = tmp_path / "policy.yaml"
|
||||
policy_path.write_text(
|
||||
"""
|
||||
_yaml_with_trailing_newline("""
|
||||
defaults:
|
||||
read: allow
|
||||
write: deny
|
||||
tools:
|
||||
deny:
|
||||
- automation_webhook_ingest
|
||||
""".strip() + "\n",
|
||||
"""),
|
||||
encoding="utf-8",
|
||||
)
|
||||
_set_base_env(monkeypatch, automation_enabled=True, policy_path=policy_path)
|
||||
@@ -126,14 +130,14 @@ def test_auto_issue_creation_denied_without_write_mode(
|
||||
"""Auto issue creation job should be denied unless write mode is enabled."""
|
||||
policy_path = tmp_path / "policy.yaml"
|
||||
policy_path.write_text(
|
||||
"""
|
||||
_yaml_with_trailing_newline("""
|
||||
defaults:
|
||||
read: allow
|
||||
write: allow
|
||||
tools:
|
||||
allow:
|
||||
- automation_auto_issue_creation
|
||||
""".strip() + "\n",
|
||||
"""),
|
||||
encoding="utf-8",
|
||||
)
|
||||
_set_base_env(monkeypatch, automation_enabled=True, policy_path=policy_path)
|
||||
|
||||
@@ -14,6 +14,10 @@ def _set_base_env(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setenv("MCP_API_KEYS", "a" * 64)
|
||||
|
||||
|
||||
def _yaml_with_trailing_newline(content: str) -> str:
|
||||
return content.strip() + "\n"
|
||||
|
||||
|
||||
def test_default_policy_allows_read_and_denies_write(
|
||||
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
||||
) -> None:
|
||||
@@ -35,14 +39,14 @@ def test_policy_global_deny(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) ->
|
||||
_set_base_env(monkeypatch)
|
||||
policy_path = tmp_path / "policy.yaml"
|
||||
policy_path.write_text(
|
||||
"""
|
||||
_yaml_with_trailing_newline("""
|
||||
defaults:
|
||||
read: allow
|
||||
write: deny
|
||||
tools:
|
||||
deny:
|
||||
- list_repositories
|
||||
""".strip() + "\n",
|
||||
"""),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
@@ -60,7 +64,7 @@ def test_repository_path_restriction(monkeypatch: pytest.MonkeyPatch, tmp_path:
|
||||
_set_base_env(monkeypatch)
|
||||
policy_path = tmp_path / "policy.yaml"
|
||||
policy_path.write_text(
|
||||
"""
|
||||
_yaml_with_trailing_newline("""
|
||||
repositories:
|
||||
acme/app:
|
||||
tools:
|
||||
@@ -69,7 +73,7 @@ repositories:
|
||||
paths:
|
||||
allow:
|
||||
- src/*
|
||||
""".strip() + "\n",
|
||||
"""),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user