feat(webapp): custom domain support, social graph assets & hardened sync prompt#110
feat(webapp): custom domain support, social graph assets & hardened sync prompt#110webmaxru wants to merge 32 commits intomicrosoft:mainfrom
Conversation
- Added favicon.ico and favicon.svg files for the application. - Included og-image.png for Open Graph sharing. - Created site.webmanifest for PWA support with icons. - Implemented generate-favicons.mjs script to automate favicon generation from SVG. - Added tests for favicon assets and Open Graph meta tags in index.html.
There was a problem hiding this comment.
Pull request overview
This PR extends the AgentRC webapp with infrastructure support for custom domains + managed TLS, adds social/SEO assets (favicons, web manifest, Open Graph/Twitter tags) with a favicon generation script and tests, and tightens the “align CLI vs webapp report” prompt to enforce webapp-only fixes.
Changes:
- Add Azure Container Apps custom-domain parameters + managed certificate workflow, and switch ACR pulls to a user-assigned managed identity.
- Add favicon/OG/PWA asset set, generation script (
sharp), and a Vitest suite verifying assets + HTML/meta/manifest wiring. - Harden the alignment prompt to treat CLI/core as the source of truth and constrain fixes to
webapp/.
Reviewed changes
Copilot reviewed 9 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
webapp/frontend/index.html |
Adds favicon <link> tags + Open Graph/Twitter meta tags. |
webapp/frontend/assets/site.webmanifest |
Adds PWA manifest referencing 192/512 icons. |
webapp/frontend/assets/favicon.svg |
Adds SVG favicon source. |
webapp/frontend/assets/favicon.ico |
Adds ICO favicon asset. |
webapp/frontend/assets/favicon-16x16.png |
Adds 16×16 PNG favicon asset. |
webapp/frontend/assets/favicon-32x32.png |
Adds 32×32 PNG favicon asset. |
webapp/frontend/assets/favicon-192x192.png |
Adds 192×192 PNG icon asset. |
webapp/frontend/assets/favicon-512x512.png |
Adds 512×512 PNG icon asset. |
webapp/frontend/assets/apple-touch-icon.png |
Adds Apple touch icon asset. |
webapp/frontend/scripts/generate-favicons.mjs |
Adds a script to regenerate PNG/ICO assets from the SVG using sharp. |
webapp/frontend/tests/favicon-og.test.js |
Adds tests validating asset presence/signatures and HTML/meta/manifest wiring. |
webapp/frontend/package.json |
Adds sharp as a dev dependency for the generator script. |
webapp/frontend/package-lock.json |
Locks sharp and its transitive deps. |
infra/webapp/main.bicep |
Adds custom domain + managed cert resources and switches ACR pull auth to a user-assigned identity. |
infra/webapp/main.bicepparam |
Adds example parameters for customDomain and customDomainCertReady. |
.github/workflows/webapp-cd.yml |
Implements two-phase infra deploy (domain registration then cert bind) and custom-domain smoke test. |
.github/prompts/align-cli-webapp-reports.prompt.md |
Tightens guidance: CLI/core is source of truth; fixes must be in webapp/ only. |
Files not reviewed (1)
- webapp/frontend/package-lock.json: Language not supported
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 21 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- webapp/frontend/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
.github/workflows/webapp-cd.yml:159
- Step 2 also hard-codes
useAcrAdminCredentials=true, so even after the domain/cert second-phase deploy the infra continues to rely on ACR admin credentials rather than the user-assigned identity path. If the intention is to harden by default, propagate a consistentuseAcrAdminCredentialsvalue (ideallyfalse) to both deploy steps.
parameters: >
containerImageTag=${{ needs.build-push.outputs.image-tag }}
ghTokenForScan=${{ secrets.GH_TOKEN_FOR_SCAN }}
useAcrAdminCredentials=true
customDomain=${{ vars.CUSTOM_DOMAIN || '' }}
customDomainCertReady=true
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 22 changed files in this pull request and generated 2 comments.
Files not reviewed (1)
- webapp/frontend/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
webapp/backend/src/server.js:143
- Only
/and the SPA catch-all return the processedindex.html. Requests to/index.htmlwill still be served byexpress.static()as the raw file containing%SITE_URL%, which defeats the goal of always emitting absolute OG/Twitter URLs for that path. Consider also serving a processed response for/index.html(or prevent static from serving it) so the placeholder never leaks.
// Serve processed index.html for root requests
app.get("/", (req, res) => {
res.type("html").send(renderIndex(req));
});
// Static frontend files (other assets)
app.use(express.static(runtime.frontendPath));
// SPA catch-all: serve processed index.html for non-API routes
app.get(/^\/(?!api\/).*/, (req, res) => {
res.type("html").send(renderIndex(req));
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…entrc into webapp-custom-domain
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
The eval workflow triggers on .github/**/*.instructions.md and .github/copilot-instructions.md path changes. Since fork PRs cannot access repository secrets (COPILOT_TOKEN), the eval step fails with an auth error and the Node process hangs until the 30-min job timeout. These Copilot instruction files will be re-added in a follow-up commit directly on the base repo where secrets are available.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
webapp/backend/tests/routes.test.js
Outdated
| afterEach(() => { | ||
| server?.close(); | ||
| // Restore original CUSTOM_DOMAIN so we don't leak state to other suites. | ||
| if (savedCustomDomain !== undefined) { | ||
| process.env.CUSTOM_DOMAIN = savedCustomDomain; | ||
| } else { | ||
| delete process.env.CUSTOM_DOMAIN; | ||
| } |
There was a problem hiding this comment.
server.close() is asynchronous, but the suite (and several tests) call server?.close() and then immediately start a new server without waiting for the close callback. This can create intermittent test flakiness and resource leaks, especially now that the new templating tests restart the server multiple times. Consider awaiting close (e.g., wrap in a Promise and await) in afterEach and before re-listening inside tests.
Summary
Extends the AgentRC web app with four improvements grouped into one PR since they shipped together on the
webappbranch.1. Configurable Custom Domain Name
Adds first-class support for binding a custom domain (with managed TLS certificate) to the Container Apps deployment and dynamically rendering absolute URLs in OG/Twitter meta tags.
Infrastructure (
infra/webapp/main.bicep)customDomain(string),customDomainCertReady(bool, two-phase deploy), anduseAcrAdminCredentials(bool, fallback for limited SP permissions)Microsoft.App/managedEnvironments/managedCertificatesresource, provisioned only when both params are setcustomDomainsarray on the Container App ingress —SniEnabledwhen cert is ready,Disabledwhile DNS is pendingacrPullIdentity) withAcrPullrole assignment — used by default instead of ACR admin credentials (admin mode still available viauseAcrAdminCredentialsflag)CI/CD (
.github/workflows/webapp-cd.yml)vars.CUSTOM_DOMAINandvars.CUSTOM_DOMAIN_CERT_READYfrom GitHub environment variablesBackend (
webapp/backend/src/server.js)parseCustomDomain()— validates and normalisesCUSTOM_DOMAINenv var to a bare hostname at startuprenderIndex()— replaces%SITE_URL%placeholders inindex.htmlat request time; uses pre-rendered HTML when a custom domain is configured, otherwise derives the base URL from theHost/X-Forwarded-HostheaderrenderIndex()for consistent OG meta across all routesParam file (
infra/webapp/main.bicepparam)customDomain,customDomainCertReady)Docker (
Dockerfile.webapp)/app/frontend/→/app/webapp/frontend/) so static assets are found at runtimeConfig (
webapp/.env.example)CUSTOM_DOMAINenv var documentationTests (
webapp/backend/tests/routes.test.js)%SITE_URL%replacement on root and SPA catch-all routes with and withoutCUSTOM_DOMAIN2. Social Graph (Open Graph & Favicon) Assets
Provides rich link-preview graphics when the webapp URL is shared on social platforms (Twitter/X, Slack, LinkedIn, etc.).
Assets added (
webapp/frontend/assets/)favicon.svg— scalable vector faviconfavicon.ico,favicon-16x16.png,favicon-32x32.png— classic faviconsapple-touch-icon.png,favicon-192x192.png,favicon-512x512.png— mobile/PWA iconsog-image.jpgandog-image.png— 1200×630 Open Graph preview imagessite.webmanifest— PWA web manifest referencing iconsHTML (
webapp/frontend/index.html)<link rel="icon">tags for all favicon sizes and formatsog:title,og:description,og:image, etc.) with%SITE_URL%placeholder for absolute URLstwitter:card,twitter:image, etc.)theme-colormeta tagTooling (
webapp/frontend/scripts/generate-favicons.mjs)sharpto regenerate all PNG sizes + ICO from the SVG sourcesharpadded towebapp/frontend/package.jsonTests (
webapp/frontend/tests/favicon-og.test.js)<link>/<meta>tags, manifest schema3. Hardened Synchronization Prompt
Updates the Copilot prompt used for aligning CLI and webapp reports.
.github/prompts/align-cli-webapp-reports.prompt.mdwebapp/only, never inpackages/core/orsrc/countStatus()excluding skipped checks and extras being non-scoredTest plan