From 6e7da8266160a13e5de9118b1853572836ebdb11 Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Sun, 22 Feb 2026 23:41:10 +0800 Subject: [PATCH 01/10] docs: add AI security review notice to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 99917d03..72911fd3 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ A minimal, zero-dependency .NET library for generating PDF documents from text and Excel (.xlsx) files. +> **Security**: All PRs are automatically reviewed by AI for security vulnerabilities. + ## Features - **Text-to-PDF** — Create PDF documents with positioned or auto-wrapped text From e285d9c3e15e5fbd2e409edf275bece947a92fb6 Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Sun, 22 Feb 2026 23:48:37 +0800 Subject: [PATCH 02/10] refactor: remove AI PR Review job and permissions; add copilot code review guidelines --- .github/copilot-code-review.md | 9 +++++++++ .github/workflows/ci.yml | 28 ---------------------------- 2 files changed, 9 insertions(+), 28 deletions(-) create mode 100644 .github/copilot-code-review.md diff --git a/.github/copilot-code-review.md b/.github/copilot-code-review.md new file mode 100644 index 00000000..342737f3 --- /dev/null +++ b/.github/copilot-code-review.md @@ -0,0 +1,9 @@ +You are a rigorous senior code reviewer tasked with preventing security vulnerabilities in code submissions. +Your assessment must be based on the code diffs of each commit. + +- Language: English +- Focus on .NET security policy and best practices +- Flag any potential SQL injection, XSS, path traversal, insecure deserialization, or other OWASP Top 10 risks +- Check for hardcoded secrets, credentials, or sensitive data exposure +- Verify proper input validation and output encoding +- Ensure secure file I/O patterns (no arbitrary file access) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c210469f..89532fe9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,6 @@ on: permissions: contents: read - pull-requests: write jobs: build: @@ -38,30 +37,3 @@ jobs: with: name: test-results path: '**/test-results.trx' - - ai-pr-review: - if: github.event_name == 'pull_request' - runs-on: ubuntu-latest - needs: build - - permissions: - contents: read - pull-requests: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: AI PR Review - uses: github/copilot-code-review-action@v1 - with: - model: gpt-4o - custom_instructions: | - You are a rigorous senior code reviewer tasked with preventing security vulnerabilities in code submissions. - Your assessment must be based on the code diffs of each commit. - - Language: English - - Focus on .NET security policy and best practices - - Flag any potential SQL injection, XSS, path traversal, insecure deserialization, or other OWASP Top 10 risks - - Check for hardcoded secrets, credentials, or sensitive data exposure - - Verify proper input validation and output encoding - - Ensure secure file I/O patterns (no arbitrary file access) From 94fd7e17c96923db22b5631a6dc8dc755ed765ae Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Sun, 22 Feb 2026 23:53:43 +0800 Subject: [PATCH 03/10] docs: trigger Copilot code review on PR #40 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72911fd3..59d50dc4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A minimal, zero-dependency .NET library for generating PDF documents from text and Excel (.xlsx) files. -> **Security**: All PRs are automatically reviewed by AI for security vulnerabilities. +> **Security**: All PRs are automatically reviewed by Copilot AI for security vulnerabilities. ## Features From 837e11e4ea96273ee371a33ecde1c7412af32146 Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Mon, 23 Feb 2026 00:04:36 +0800 Subject: [PATCH 04/10] ci: add AI security scan job with pass/fail check --- .github/workflows/ci.yml | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89532fe9..9090d943 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ on: permissions: contents: read + pull-requests: read jobs: build: @@ -37,3 +38,98 @@ jobs: 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: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + 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.") + + # Build JSON payload safely using jq + PAYLOAD=$(jq -n \ + --arg instructions "$INSTRUCTIONS" \ + --arg diff "$DIFF" \ + '{ + model: "gpt-4o-mini", + 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 https://api.openai.com/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $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 "=================================" + + # Extract JSON from response (handle markdown code blocks) + JSON_RESULT=$(echo "$CONTENT" | sed -n 's/.*\({.*}\).*/\1/p' | head -1) + if [ -z "$JSON_RESULT" ]; then + JSON_RESULT="$CONTENT" + fi + + PASSED=$(echo "$JSON_RESULT" | jq -r '.passed // empty' 2>/dev/null) + + if [ "$PASSED" = "false" ]; then + echo "" + echo "::error::AI Security Review FAILED - security issues detected" + echo "$JSON_RESULT" | 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 pass" + fi + + - name: Skip notice + if: steps.diff.outputs.skip == 'true' + run: echo "✅ No code changes to review" From 6bb657150f63dc313fd00bd86fac815525d499a6 Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Mon, 23 Feb 2026 00:09:11 +0800 Subject: [PATCH 05/10] ci: switch AI security scan to Azure AI Foundry API --- .github/workflows/ci.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9090d943..0e7209b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,9 @@ jobs: - name: AI Security Review if: steps.diff.outputs.skip != 'true' env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + 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) @@ -77,12 +79,14 @@ jobs: 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" \ '{ - model: "gpt-4o-mini", 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) } @@ -90,9 +94,9 @@ jobs: temperature: 0.1 }') - RESPONSE=$(curl -s https://api.openai.com/v1/chat/completions \ + RESPONSE=$(curl -s "$URL" \ -H "Content-Type: application/json" \ - -H "Authorization: Bearer $OPENAI_API_KEY" \ + -H "api-key: $AZURE_OPENAI_API_KEY" \ -d "$PAYLOAD") # Extract content From 651576b5b49048b9ba66497256408f5976014bb2 Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Mon, 23 Feb 2026 00:15:12 +0800 Subject: [PATCH 06/10] docs: trigger CI to test Azure AI security scan --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 59d50dc4..a172b630 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A minimal, zero-dependency .NET library for generating PDF documents from text and Excel (.xlsx) files. -> **Security**: All PRs are automatically reviewed by Copilot AI for security vulnerabilities. +> **Security**: All PRs are automatically reviewed by Copilot AI and Azure AI security scan for vulnerabilities. ## Features From 68a13eef96b9d76154b11bc864664f1de62be4e2 Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Mon, 23 Feb 2026 00:21:30 +0800 Subject: [PATCH 07/10] fix: fix multi-line JSON parsing in AI security scan --- .github/workflows/ci.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e7209b0..0e5cf1b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -112,18 +112,14 @@ jobs: echo "$CONTENT" echo "=================================" - # Extract JSON from response (handle markdown code blocks) - JSON_RESULT=$(echo "$CONTENT" | sed -n 's/.*\({.*}\).*/\1/p' | head -1) - if [ -z "$JSON_RESULT" ]; then - JSON_RESULT="$CONTENT" - fi - - PASSED=$(echo "$JSON_RESULT" | jq -r '.passed // empty' 2>/dev/null) + # 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 "$JSON_RESULT" | jq -r '.issues[]? // empty' 2>/dev/null | while read -r issue; do + echo "$CLEAN_CONTENT" | jq -r '.issues[]? // empty' 2>/dev/null | while read -r issue; do echo "::warning::$issue" done exit 1 @@ -131,7 +127,8 @@ jobs: echo "" echo "✅ AI Security Review PASSED - no security issues found" else - echo "::warning::Could not parse AI review result, treating as pass" + echo "::warning::Could not parse AI review result, treating as FAIL for safety" + exit 1 fi - name: Skip notice From d4f524d2fc2b2a62de2a21e7f9292e7fbc69af43 Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Mon, 23 Feb 2026 00:23:22 +0800 Subject: [PATCH 08/10] fix: improve AI review prompt to ignore CI config false positives --- .github/copilot-code-review.md | 7 ++++++- .github/workflows/ci.yml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/copilot-code-review.md b/.github/copilot-code-review.md index 342737f3..94476f63 100644 --- a/.github/copilot-code-review.md +++ b/.github/copilot-code-review.md @@ -4,6 +4,11 @@ Your assessment must be based on the code diffs of each commit. - Language: English - Focus on .NET security policy and best practices - Flag any potential SQL injection, XSS, path traversal, insecure deserialization, or other OWASP Top 10 risks -- Check for hardcoded secrets, credentials, or sensitive data exposure +- Check for hardcoded secrets, credentials, or sensitive data exposure in application source code - Verify proper input validation and output encoding - Ensure secure file I/O patterns (no arbitrary file access) + +IMPORTANT: Do NOT flag the following as security issues: +- Using ${{ secrets.* }} in GitHub Actions workflows (this is the correct way to use secrets in CI) +- Changes to CI/CD configuration files (.yml/.yaml under .github/workflows/) unless they contain actual hardcoded credentials +- Changes to documentation files (.md) unless they expose sensitive information diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e5cf1b4..08fe81c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,7 +89,7 @@ jobs: '{ 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) } + { role: "user", content: ("Review this code diff for security vulnerabilities in APPLICATION SOURCE CODE ONLY. Respond ONLY with a JSON object (no markdown, no code blocks): {\"passed\": true/false, \"issues\": [\"description1\", \"description2\"]}. Set passed=true if no security issues found in application code, passed=false only for real security concerns like SQL injection, XSS, path traversal, hardcoded credentials in source code, etc. Do NOT flag CI/CD workflow configuration or documentation changes as issues.\n\nDiff:\n" + $diff) } ], temperature: 0.1 }') From b996f661d3ca7d9b1f6f28d71601fa3832a1d30d Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Mon, 23 Feb 2026 00:26:41 +0800 Subject: [PATCH 09/10] fix: fix jq boolean parsing and limit diff to source code only --- .github/workflows/ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08fe81c8..2d153f70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,7 +53,7 @@ jobs: - name: Get PR diff id: diff run: | - DIFF=$(git diff origin/${{ github.base_ref }}...HEAD -- '*.cs' '*.csproj' '*.yml' '*.yaml' '*.json' '*.xml' '*.config' || true) + DIFF=$(git diff origin/${{ github.base_ref }}...HEAD -- '*.cs' '*.csproj' || true) if [ -z "$DIFF" ]; then echo "No code changes detected." echo "skip=true" >> $GITHUB_OUTPUT @@ -114,12 +114,13 @@ jobs: # 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) + # Use 'if .passed then "true" else "false" end' to handle boolean false correctly + PASSED=$(echo "$CLEAN_CONTENT" | jq -r 'if .passed == true then "true" elif .passed == false then "false" else "unknown" end' 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 "$CLEAN_CONTENT" | jq -r '.issues[]?' 2>/dev/null | while read -r issue; do echo "::warning::$issue" done exit 1 From 30b2201966d235546ba0d04fa40db14a743359e9 Mon Sep 17 00:00:00 2001 From: Wei Lin Date: Mon, 23 Feb 2026 00:30:23 +0800 Subject: [PATCH 10/10] chore: add MiniPdf.wiki to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 6752c8bc..e3258262 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ Desktop.ini ## NuGet *.nupkg + +## Wiki +MiniPdf.wiki/