feat: AgentRC Readiness Scanner Web App#90
Conversation
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
There was a problem hiding this comment.
Pull request overview
Introduces a standalone “AgentRC Readiness Scanner” web surface (Express backend + vanilla JS frontend) that runs readiness scans via @agentrc/core, with supporting Docker, Azure Container Apps infra (Bicep), and dedicated CI/CD workflows. Root-level lint/test config is adjusted to ignore webapp/** so the existing repo CI doesn’t attempt to parse or run webapp-only dependencies.
Changes:
- Added Express backend routes for scanning repos, serving config/health, and optional report sharing with storage + validation.
- Added a static frontend SPA (HTML/CSS/JS) that handles repo routing/history and renders a CLI-like readiness report (with optional share UX).
- Added Dockerfile, docker-compose, Azure infra templates, and GitHub Actions workflows for webapp CI/CD; updated root ESLint/Vitest/Prettier ignores.
Reviewed changes
Copilot reviewed 37 out of 38 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| webapp/frontend/tests/repo-location.test.js | Unit tests for frontend repo URL/path parsing helpers. |
| webapp/frontend/src/report.js | Frontend report renderer (HTML generation, share button, service info). |
| webapp/frontend/src/repo-location.js | Frontend repo reference parsing + browser history sync helpers. |
| webapp/frontend/src/main.css | Web UI styling (theme, layout, report visuals). |
| webapp/frontend/src/app.js | Frontend orchestration: routing, scan execution, progress/error UI, theme toggle. |
| webapp/frontend/src/api.js | Frontend HTTP client for backend API endpoints. |
| webapp/frontend/index.html | SPA shell, scan form, inline theme init, static asset wiring. |
| webapp/docker-compose.yml | Local container run configuration (env + volume for reports). |
| webapp/backend/vitest.config.js | Backend Vitest configuration. |
| webapp/backend/tests/url-parser.test.js | Tests for backend SSRF-safe GitHub URL parser. |
| webapp/backend/tests/storage.test.js | Tests for report storage (memory mode). |
| webapp/backend/tests/routes.test.js | Contract tests for API routes (scan/config/health/report). |
| webapp/backend/tests/report-validator.test.js | Tests for shared report normalization/validation. |
| webapp/backend/tests/cleanup.test.js | Tests for temp directory creation/removal utilities. |
| webapp/backend/src/utils/url-parser.js | SSRF-safe GitHub URL parsing + validation errors. |
| webapp/backend/src/utils/cleanup.js | Temp dir lifecycle + stale temp sweep utilities. |
| webapp/backend/src/services/storage.js | File/memory report persistence with TTL cleanup. |
| webapp/backend/src/services/scanner.js | Clone + readiness scan orchestration, concurrency limits, stale sweep timer. |
| webapp/backend/src/services/report-validator.js | Shared report validation/normalization before persisting. |
| webapp/backend/src/server.js | Express app factory + runtime config + static frontend serving. |
| webapp/backend/src/routes/scan.js | /api/scan endpoint: validate input and run scan. |
| webapp/backend/src/routes/report.js | /api/report endpoints: save and fetch shared reports. |
| webapp/backend/src/routes/config.js | /api/config endpoint: expose public runtime config to frontend. |
| webapp/backend/src/middleware/rate-limiter.js | Rate limiting for scan/report endpoints. |
| webapp/backend/src/middleware/error-handler.js | Centralized error → HTTP status mapping and safe responses. |
| webapp/backend/package.json | Backend package metadata, scripts, and dependencies. |
| webapp/.env.example | Example env vars for local dev and sharing configuration. |
| vitest.config.ts | Root Vitest excludes webapp/** to avoid discovering webapp tests/deps. |
| infra/webapp/main.json | Generated ARM template for Azure Container Apps deployment. |
| infra/webapp/main.bicepparam | Default parameter file for deploying the webapp infra. |
| infra/webapp/main.bicep | Bicep source for Azure infra (ACA, storage, insights, logs). |
| eslint.config.js | Root ESLint ignores webapp/**. |
| Dockerfile.webapp | Multi-stage build for a single-container deployment (backend + static frontend). |
| .prettierignore | Ignores webapp/ and Dockerfile.webapp in root formatting checks. |
| .github/workflows/webapp-ci.yml | Webapp-scoped CI: backend tests + Docker build + Trivy scan. |
| .github/workflows/webapp-cd.yml | Webapp CD: build/push image + scan + deploy via Bicep + smoke test. |
| .github/prompts/plan-agentrcWebapp.prompt.md | Design/plan prompt documenting the intended architecture and steps. |
Files not reviewed (1)
- webapp/backend/package-lock.json: Language not supported
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 36 out of 37 changed files in this pull request and generated 6 comments.
Files not reviewed (1)
- webapp/backend/package-lock.json: Language not supported
Comments suppressed due to low confidence (3)
webapp/backend/src/server.js:67
- The CSP explicitly allows
'unsafe-inline'scripts/styles. Since this app already ships module scripts, consider removing'unsafe-inline'by moving the inline theme bootstrap into a static JS file (or using nonces) to keep CSP effective against XSS.
// Security headers
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:"],
connectSrc: ["'self'"]
}
}
})
webapp/backend/src/server.js:72
app.use(cors())enables CORS for all origins by default. If the API is intended to be same-origin only (or limited to a known set of domains), configure allowed origins explicitly to reduce the risk of third-party sites driving scans from browsers.
app.use(cors());
app.use(express.json({ limit: "1mb" }));
webapp/backend/src/server.js:94
- In the SPA catch-all route, the
sendFilecallback callsnext()when an error occurs. This drops the underlying error and can result in confusing 404s or partially-sent responses. Pass the error through (next(err)) so it reaches the error handler correctly.
// SPA catch-all: serve index.html for non-API routes
app.get(/^\/(?!api\/).*/, (_req, res, next) => {
res.sendFile("index.html", { root: runtime.frontendPath }, (err) => {
if (err) next();
});
});
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 38 out of 40 changed files in this pull request and generated 6 comments.
Files not reviewed (2)
- webapp/backend/package-lock.json: Language not supported
- webapp/frontend/package-lock.json: Language not supported
Comments suppressed due to low confidence (2)
webapp/frontend/src/report.js:224
c.statusis interpolated directly into a class attribute (ai-criterion-icon ${c.status}) withininnerHTML. If a shared report contains a maliciousstatusvalue, this can lead to attribute injection/stored XSS. Constrainstatusto an allowlist (pass/fail/skip) before rendering, or build DOM nodes and setclassNamevia safe mapping.
webapp/frontend/src/report.js:338c.statusis interpolated directly intoclass="criterion-status ${c.status}"in multiple sections. Ifstatusis not strictly validated/normalized, this is an injection vector when usinginnerHTML. Recommend restrictingstatusto a known set and using a safe mapping for CSS classes.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 38 out of 40 changed files in this pull request and generated 6 comments.
Files not reviewed (2)
- webapp/backend/package-lock.json: Language not supported
- webapp/frontend/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
webapp/frontend/src/report.js:278
- Same issue as the hero section:
report.achievedLevel || 1will incorrectly coerce0to1, so shared reports withachievedLevel: 0won’t render accurately. Use a defaulting approach that preserves 0.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 38 out of 40 changed files in this pull request and generated 5 comments.
Files not reviewed (2)
- webapp/backend/package-lock.json: Language not supported
- webapp/frontend/package-lock.json: Language not supported
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 43 out of 45 changed files in this pull request and generated 4 comments.
Files not reviewed (2)
- webapp/backend/package-lock.json: Language not supported
- webapp/frontend/package-lock.json: Language not supported
fix: resolve frontend path using fileURLToPath for better compatibility fix: enhance theme toggle functionality to handle localStorage errors gracefully
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 42 changed files in this pull request and generated 1 comment.
Files not reviewed (2)
- webapp/backend/package-lock.json: Language not supported
- webapp/frontend/package-lock.json: Language not supported
- Changed the start script to run the bundled server from the dist directory. - Added a build script to bundle the application using esbuild. - Introduced a new esbuild configuration file to handle the bundling of the server. - Updated dependencies to include esbuild and adjusted the location of @agentrc/core.
…a fields to prevent XSS fix(report): use safe number handling for app and area summaries in report rendering fix(Dockerfile): include node_modules from deps for backend build
fix(cleanup): streamline error handling in removeTempDir function
…e naming fix(scanner): encode GitHub token in clone URL to prevent issues with special characters
AgentRC Readiness Scanner — Web Surface
A lightweight web application that exposes AgentRC readiness scanning through a browser interface. The webapp leverages
@agentrc/coreservices directly — importingcloneRepofrom@agentrc/core/services/gitandrunReadinessReportfrom@agentrc/core/services/readiness— to be as minimally invasive and standalone as possible. No core logic is duplicated; the webapp is a thin HTTP + UI layer on top of the existing engine.Live App
https://agentrc-webapp.redsand-b56d7588.eastus.azurecontainerapps.io
What's Included
webapp/backend/webapp/frontend/infra/webapp/.github/workflows/webapp-ci.yml.github/workflows/webapp-cd.ymlDockerfile.webapptsxfor@agentrc/coreTypeScript imports at runtime.Architecture
The report renderer matches the CLI
readiness --htmloutput format — same pillars, maturity levels, and color coding.Root CI Compatibility
The webapp is designed to be standalone, but the root CI workflows (ESLint, Prettier, vitest) automatically pick up all files in the repo. Since root
npm installdoesn't installwebapp/backend/node_modules, webapp files would fail in root CI. These minimal changes to root config files ensure the root CI ignores the webapp directory (the webapp has its own dedicated CI workflow):eslint.config.js"webapp/**"to globalignores@typescript-eslint/parserwithparserOptions.project: "./tsconfig.json". Webapp's plain JS files aren't in the root TS project and would fail parsing.vitest.config.tsexclude: ["webapp/**", ...]totestconfigwebapp/backend/tests/*.test.jsbut can't resolve their imports (express,cors, etc.) since those deps live only inwebapp/backend/node_modules.tsconfig.json.prettierignorewebapp/andDockerfile.webappAll root CI checks pass: Lint & Format, Typecheck, Build & Verify, and all 3 test matrices (Node 20/22, Ubuntu/Windows).
Repository Setup Required
To deploy your own instance, configure these GitHub repository secrets (in a
productionenvironment):AZURE_CLIENT_IDAZURE_TENANT_IDAZURE_SUBSCRIPTION_IDGH_TOKEN_FOR_SCANreposcope for private repos, or just public access)The Azure AD app needs Contributor role on the subscription and a federated credential for
repo:<owner>/<repo>:environment:production.Key Design Decisions
webapp/,infra/webapp/, and workflow files@agentrc/coreimports — no wrapper, no abstraction layer; the scanner service calls core functions directlydocker-compose upfor local dev, CD pipeline for AzurecontainerStartupStrategyparameter (currently set tokeep-warm)