Skip to content

feat: AgentRC Readiness Scanner Web App#90

Merged
danielmeppiel merged 34 commits intomicrosoft:mainfrom
webmaxru:webapp
Apr 1, 2026
Merged

feat: AgentRC Readiness Scanner Web App#90
danielmeppiel merged 34 commits intomicrosoft:mainfrom
webmaxru:webapp

Conversation

@webmaxru
Copy link
Copy Markdown
Contributor

AgentRC Readiness Scanner — Web Surface

A lightweight web application that exposes AgentRC readiness scanning through a browser interface. The webapp leverages @agentrc/core services directly — importing cloneRepo from @agentrc/core/services/git and runReadinessReport from @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

Area Files Description
Backend webapp/backend/ Express server with scan, config, and report-sharing routes. Rate-limited, Helmet-secured, health-checked.
Frontend webapp/frontend/ Vanilla JS SPA — scan form, progress UI, CLI-matching report renderer with dark/light theme.
Infrastructure infra/webapp/ Bicep templates for Azure Container Apps (Consumption plan), Log Analytics, App Insights, Storage.
CI .github/workflows/webapp-ci.yml PR checks — lint, typecheck, unit tests (58 tests).
CD .github/workflows/webapp-cd.yml Build → GHCR push → Trivy scan → Bicep deploy → smoke test.
Docker Dockerfile.webapp Multi-stage Node 24 Alpine build. Uses tsx for @agentrc/core TypeScript imports at runtime.

Architecture

Browser → Express API → @agentrc/core (git clone + readiness scan) → JSON report → Frontend renderer

The report renderer matches the CLI readiness --html output 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 install doesn't install webapp/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):

File Change Reason
eslint.config.js Added "webapp/**" to global ignores Root ESLint uses @typescript-eslint/parser with parserOptions.project: "./tsconfig.json". Webapp's plain JS files aren't in the root TS project and would fail parsing.
vitest.config.ts Added exclude: ["webapp/**", ...] to test config Root vitest would discover webapp/backend/tests/*.test.js but can't resolve their imports (express, cors, etc.) since those deps live only in webapp/backend/node_modules.
tsconfig.json No net change (was temporarily added, then reverted) Webapp doesn't need to be in the root TypeScript project.
.prettierignore Added webapp/ and Dockerfile.webapp Prettier can't parse Dockerfiles (syntax error). Webapp frontend files have their own formatting conventions.

All 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 production environment):

Secret Description
AZURE_CLIENT_ID Azure AD app registration client ID (OIDC federated credential)
AZURE_TENANT_ID Azure AD tenant ID
AZURE_SUBSCRIPTION_ID Target Azure subscription
GH_TOKEN_FOR_SCAN GitHub PAT for cloning repos during scans (needs repo scope 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

  • Zero core changes — all new files live under webapp/, infra/webapp/, and workflow files
  • Minimal root config touches — only ignore/exclude patterns added so root CI skips the webapp directory
  • Direct @agentrc/core imports — no wrapper, no abstraction layer; the scanner service calls core functions directly
  • Standalone deployabledocker-compose up for local dev, CD pipeline for Azure
  • Report sharing — optional Azure File Share–backed persistent storage for shareable report URLs
  • Scale-to-zero or keep-warm — configurable via Bicep containerStartupStrategy parameter (currently set to keep-warm)

@webmaxru webmaxru requested a review from pierceboggan as a code owner March 31, 2026 09:15
Copilot AI review requested due to automatic review settings March 31, 2026 09:15
@webmaxru webmaxru requested a review from digitarald as a code owner March 31, 2026 09:15
@github-advanced-security
Copy link
Copy Markdown

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:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copilot AI review requested due to automatic review settings March 31, 2026 09:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 sendFile callback calls next() 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();
    });
  });

Copilot AI review requested due to automatic review settings March 31, 2026 10:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.status is interpolated directly into a class attribute (ai-criterion-icon ${c.status}) within innerHTML. If a shared report contains a malicious status value, this can lead to attribute injection/stored XSS. Constrain status to an allowlist (pass/fail/skip) before rendering, or build DOM nodes and set className via safe mapping.
    webapp/frontend/src/report.js:338
  • c.status is interpolated directly into class="criterion-status ${c.status}" in multiple sections. If status is not strictly validated/normalized, this is an injection vector when using innerHTML. Recommend restricting status to a known set and using a safe mapping for CSS classes.

Copilot AI review requested due to automatic review settings March 31, 2026 11:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 || 1 will incorrectly coerce 0 to 1, so shared reports with achievedLevel: 0 won’t render accurately. Use a defaulting approach that preserves 0.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copilot AI review requested due to automatic review settings March 31, 2026 21:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

webmaxru added 2 commits April 1, 2026 00:02
- 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.
Copilot AI review requested due to automatic review settings March 31, 2026 22:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 40 out of 42 changed files in this pull request and generated 4 comments.

Files not reviewed (1)
  • webapp/frontend/package-lock.json: Language not supported

webmaxru added 2 commits April 1, 2026 00:16
…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
Copilot AI review requested due to automatic review settings March 31, 2026 22:21
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 40 out of 42 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • webapp/frontend/package-lock.json: Language not supported

Copilot AI review requested due to automatic review settings March 31, 2026 22:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 41 out of 43 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • webapp/frontend/package-lock.json: Language not supported

…e naming

fix(scanner): encode GitHub token in clone URL to prevent issues with special characters
@danielmeppiel danielmeppiel merged commit d64bfc3 into microsoft:main Apr 1, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants