Skip to content
Merged
65 changes: 65 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# JioPC Testing Agent CI/CD Pipeline

## What This Pipeline Does

The GitHub Actions pipeline automatically triggers on every Pull Request to the repository. It spins up a clean, ephemeral Ubuntu 24.04 environment and installs the JioPC testing agent dependencies. The pipeline then runs the web validation suite (Part A), securely calls the OpenAI API to analyze the JSON Lines log file via the agent's internal LLM module, and automatically extracts and posts the test counts and the LLM recommendation directly as a comment on the Pull Request. This gives engineers immediate AI-powered feedback on whether the OS patch is safe to promote.

## Trigger Conditions

The CI/CD pipeline is designed to execute automatically on:
- **Pull Requests:** Whenever a PR is opened, reopened, or when new commits are synchronized to an open PR targeting `main`.
- **Manual Trigger:** The workflow supports `workflow_dispatch`, allowing developers to manually run the pipeline from the GitHub Actions UI for testing or demonstration purposes.

## Pipeline Steps

| Step | Name | What it does |
|------|------|--------------|
| 1 | Checkout | Clones the repository code into the runner |
| 2 | Python setup | Installs Python 3.11 |
| 3 | System deps | Installs underlying system requirements (`xvfb`, `xdg-utils`, `wmctrl`) |
| 4 | Python deps | Installs all required pip packages including `playwright` and `openai` |
| 5 | Playwright | Downloads headless Chromium and its OS-level dependencies (`--with-deps`) |
| 6 | Log dir | Creates `~/.local/share/jiopc/agent/` to safely capture test logs |
| 7 | Run agent | Executes the testing agent (Part A) and captures the standard output |
| 8 | Find log | Automatically locates the latest JSONL generated log file by timestamp |
| 9 | LLM analysis | Runs `analyse.py` against the log file with the OpenAI API |
| 10 | Extract summary | Uses Python to safely parse the `summary: true` block for pass/fail counts |
| 11 | PR comment | Uses `actions/github-script` to post the extracted metrics and LLM report to the PR |
| 12 | Check result | Forcefully fails the pipeline if any `FAIL` results are detected |

## Required GitHub Secrets

To allow the pipeline to securely communicate with the LLM without exposing credentials in the public codebase, the following repository secret must be configured:

| Secret name | What it is | Where to set it |
|-------------|------------|-----------------|
| `LLM_API_KEY` | BharatCode API key for LLM analysis | GitHub repo → Settings → Secrets and variables → Actions → New repository secret |
| `SMTP_PASS` | Gmail App Password for email summary (Optional) | GitHub repo → Settings → Secrets and variables → Actions → New repository secret |

## How to Read the PR Comment

When the pipeline posts the automated PR comment, it provides a comprehensive overview:
- ✅ **Green (PASS):** Indicates that all executed tests passed successfully (or were safely blocked).
- ❌ **Red (FAIL):** Indicates that at least one functional failure was detected during the run.
- **BLOCKED Results:** These are explicitly expected for Jio URLs (like JioSaavn, JioCloud) that sit behind Cloudflare/Bot protection when accessed via headless Chromium. They **do not** indicate failures.
- **LLM Analysis:** This section contains the deep-dive diagnostic report and states the clear **PROMOTE** or **HOLD** recommendation from the AI.

## What `GITHUB_TOKEN` is

The `GITHUB_TOKEN` is a special authentication token automatically provided by GitHub Actions at runtime. No manual setup is needed. It is strictly used in Step 11 (`actions/github-script`) to authenticate the bot to post the PR comment on your behalf. Because the workflow file explicitly sets `permissions: pull-requests: write`, the token operates securely and with least-privilege.

## Running Manually

If you need to trigger a test run without opening a Pull Request:
1. Go to your GitHub repository and click the **Actions** tab.
2. Select **JioPC Testing Agent** from the left-hand sidebar.
3. Click the **Run workflow** dropdown on the right side.
4. Select your target branch and click the green **Run workflow** button.

---

> **Note on Scope:**
> The CI pipeline runs Part A (web testing) only. Parts B and C require the JioPC Gold Image environment with pre-installed native applications and desktop folder structure. To run the full agent including all three components, use a JioPC VM or an Ubuntu 24.04 + LxQt environment with the Gold Image installed.
>
> Full run command (on JioPC VM):
> `jiopc-agent --config /usr/lib/jiopc-agent/config/jiopc-agent.yaml --analyse`
164 changes: 164 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
name: JioPC Testing Agent

on:
pull_request:
types: [opened, reopened, synchronize]
workflow_dispatch:

jobs:
test-and-analyse:
runs-on: ubuntu-24.04
permissions:
pull-requests: write
contents: read
env:
LLM_BASE_URL: https://bharatcode.ai/api/model/v1
LLM_MODEL: bharatcode:qwen36-35b-q6-256k-vision
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
SMTP_PASS: ${{ secrets.SMTP_PASS }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install system dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y xvfb xdg-utils wmctrl

- name: Install Python dependencies
run: |
pip install --upgrade pip
pip install pyyaml psutil pyxdg playwright openai

- name: Install Playwright Chromium
run: python3 -m playwright install chromium --with-deps

- name: Create log directory
run: mkdir -p ~/.local/share/jiopc/agent

- name: Run agent
run: |
python3 src/jiopc_agent.py \
--config config/jiopc-agent.yaml \
--part A \
2>&1 | tee /tmp/agent_output.txt
continue-on-error: true

- name: Find log file
run: |
LOG_FILE=$(ls -t ~/.local/share/jiopc/agent/*.jsonl 2>/dev/null | head -1)
if [ -z "$LOG_FILE" ]; then
echo "ERROR: No log file found"
exit 1
fi
echo "LOG_FILE=$LOG_FILE" >> $GITHUB_ENV
echo "Found log file: $LOG_FILE"
cat "$LOG_FILE"

- name: Run LLM Analysis
run: |
python3 src/analyse.py --log "$LOG_FILE" > /tmp/analysis_output.txt 2>&1
echo "--- LLM Analysis Output ---"
cat /tmp/analysis_output.txt

# Save analysis output to env for PR comment
{
echo 'ANALYSIS_OUTPUT<<EOF'
cat /tmp/analysis_output.txt
echo 'EOF'
} >> $GITHUB_ENV
env:
LLM_BASE_URL: ${{ env.LLM_BASE_URL }}
LLM_MODEL: ${{ env.LLM_MODEL }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
continue-on-error: true

- name: Extract test summary
run: |
# Read the summary line from the JSON Lines log
SUMMARY=$(python3 -c "
import json, sys
with open('$LOG_FILE') as f:
for line in f:
try:
obj = json.loads(line.strip())
if obj.get('summary'):
print(json.dumps(obj, indent=2))
sys.exit(0)
except Exception:
pass
print('{}')
")

TOTAL=$(echo "$SUMMARY" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('total',0))")
PASS=$(echo "$SUMMARY" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('pass',0))")
FAIL=$(echo "$SUMMARY" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('fail',0))")
BLOCKED=$(echo "$SUMMARY" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('blocked',0))")

echo "TOTAL=$TOTAL" >> $GITHUB_ENV
echo "PASS=$PASS" >> $GITHUB_ENV
echo "FAIL=$FAIL" >> $GITHUB_ENV
echo "BLOCKED=$BLOCKED" >> $GITHUB_ENV

echo "Total: $TOTAL | Pass: $PASS | Fail: $FAIL | Blocked: $BLOCKED"

- name: Post PR comment
uses: actions/github-script@v7
if: github.event_name == 'pull_request'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const total = process.env.TOTAL || '0';
const pass = process.env.PASS || '0';
const fail = process.env.FAIL || '0';
const blocked = process.env.BLOCKED || '0';
const analysis = process.env.ANALYSIS_OUTPUT || 'Analysis not available';

const statusEmoji = parseInt(fail) === 0 ? '✅' : '❌';
const statusText = parseInt(fail) === 0 ? 'PASS' : 'FAIL';

const body = [
'## ' + statusEmoji + ' JioPC Testing Agent — ' + statusText,
'',
'| Metric | Count |',
'|--------|-------|',
'| Total Tests | ' + total + ' |',
'| ✅ Passed | ' + pass + ' |',
'| ❌ Failed | ' + fail + ' |',
'| 🔒 Blocked (bot protection) | ' + blocked + ' |',
'',
'> **Note:** BLOCKED results are expected for Jio URLs behind',
'> Cloudflare protection and do not indicate failures.',
'',
'---',
'',
'## 🤖 LLM Analysis',
'',
'```',
analysis,
'```',
'',
'---',
'_Triggered by commit ' + context.sha.substring(0, 7) + '_'
].join('\n');

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});

- name: Check result
run: |
if [ "$FAIL" -gt "0" ]; then
echo "Pipeline failed: $FAIL test(s) failed"
exit 1
fi
echo "All tests passed or blocked. Pipeline successful."
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ The logs are written in **JSON Lines (JSONL)** format, making them highly machin

> **IMPORTANT:** `BLOCKED` is **NOT** a failure. It means a Jio-protected URL triggered expected bot detection in the headless browser. The LLM is explicitly trained to understand this distinction.

## CI/CD Integration (Bonus Feature)

The repository includes a production-ready **GitHub Actions Pipeline** (`.github/workflows/jiopc-agent-ci.yml`).

Whenever a Pull Request is opened against the `main` branch, the pipeline will automatically:
1. Spin up an Ubuntu 24.04 runner.
2. Build and install the `.deb` package dynamically.
3. Run the full validation suite (Parts A, B, and C) inside a headless `xvfb` frame.
4. Extract the LLM Analysis and **post it as a comment directly on the Pull Request** so engineers can immediately see if the patch is safe to promote.

*(To enable this on your fork, simply add `LLM_API_KEY`, `LLM_MODEL`, and `LLM_BASE_URL` to your GitHub Repository Secrets).*

## Benchmarking

To prove that the agent complies with the strict hackathon resource constraints (< 150MB RAM, < 20% CPU), run the included benchmark script:
Expand Down
Loading