docs: add AI security review notice to README #27
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: | |
| push: | |
| branches: [ main, master ] | |
| pull_request: | |
| branches: [ main, master ] | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '9.0.x' | |
| - name: Restore dependencies | |
| run: dotnet restore | |
| - name: Build | |
| run: dotnet build --no-restore --configuration Release | |
| - name: Test | |
| run: dotnet test --no-build --configuration Release --verbosity normal --logger "trx;LogFileName=test-results.trx" | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: test-results | |
| path: '**/test-results.trx' | |
| ai-security-scan: | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| needs: build | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get PR diff | |
| id: diff | |
| run: | | |
| DIFF=$(git diff origin/${{ github.base_ref }}...HEAD -- '*.cs' '*.csproj' '*.yml' '*.yaml' '*.json' '*.xml' '*.config' || true) | |
| if [ -z "$DIFF" ]; then | |
| echo "No code changes detected." | |
| echo "skip=true" >> $GITHUB_OUTPUT | |
| else | |
| # Save diff to file to avoid shell escaping issues | |
| echo "$DIFF" > /tmp/pr_diff.txt | |
| echo "skip=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: AI Security Review | |
| if: steps.diff.outputs.skip != 'true' | |
| env: | |
| AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} | |
| AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} | |
| AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} | |
| run: | | |
| DIFF=$(cat /tmp/pr_diff.txt) | |
| # Truncate diff if too large (max ~12000 chars to fit in context) | |
| if [ ${#DIFF} -gt 12000 ]; then | |
| DIFF="${DIFF:0:12000}... [truncated]" | |
| fi | |
| INSTRUCTIONS=$(cat .github/copilot-code-review.md 2>/dev/null || echo "Review for security issues.") | |
| API_VERSION="2025-01-01-preview" | |
| URL="${AZURE_OPENAI_ENDPOINT%/}/openai/deployments/${AZURE_OPENAI_DEPLOYMENT}/chat/completions?api-version=${API_VERSION}" | |
| # Build JSON payload safely using jq | |
| PAYLOAD=$(jq -n \ | |
| --arg instructions "$INSTRUCTIONS" \ | |
| --arg diff "$DIFF" \ | |
| '{ | |
| messages: [ | |
| { role: "system", content: $instructions }, | |
| { role: "user", content: ("Review this code diff for security vulnerabilities. Respond with a JSON object: {\"passed\": true/false, \"issues\": [\"issue1\", \"issue2\"]}. Set passed=true if no security issues found, passed=false if there are security concerns.\n\nDiff:\n" + $diff) } | |
| ], | |
| temperature: 0.1 | |
| }') | |
| RESPONSE=$(curl -s "$URL" \ | |
| -H "Content-Type: application/json" \ | |
| -H "api-key: $AZURE_OPENAI_API_KEY" \ | |
| -d "$PAYLOAD") | |
| # Extract content | |
| CONTENT=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // empty') | |
| if [ -z "$CONTENT" ]; then | |
| echo "::error::Failed to get AI review response" | |
| echo "$RESPONSE" | jq . | |
| exit 1 | |
| fi | |
| echo "=== AI Security Review Result ===" | |
| echo "$CONTENT" | |
| echo "=================================" | |
| # Parse JSON from response: strip markdown code blocks, then parse with jq | |
| CLEAN_CONTENT=$(echo "$CONTENT" | sed '/^```/d') | |
| PASSED=$(echo "$CLEAN_CONTENT" | jq -r '.passed // empty' 2>/dev/null) | |
| if [ "$PASSED" = "false" ]; then | |
| echo "" | |
| echo "::error::AI Security Review FAILED - security issues detected" | |
| echo "$CLEAN_CONTENT" | jq -r '.issues[]? // empty' 2>/dev/null | while read -r issue; do | |
| echo "::warning::$issue" | |
| done | |
| exit 1 | |
| elif [ "$PASSED" = "true" ]; then | |
| echo "" | |
| echo "✅ AI Security Review PASSED - no security issues found" | |
| else | |
| echo "::warning::Could not parse AI review result, treating as FAIL for safety" | |
| exit 1 | |
| fi | |
| - name: Skip notice | |
| if: steps.diff.outputs.skip == 'true' | |
| run: echo "✅ No code changes to review" |