You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: improve domain scaffolding with container-first deploy, uniqueString, and lessons learned
- Add Lessons Learned section to agent with 8 codified patterns from Code Quality iteration
- Container-first deployment: all 5 demo apps deploy as Docker containers via ACR + Web App for Containers
- Global uniqueness: all Bicep templates use uniqueString(resourceGroup().id) for multi-student workshops
- OIDC JSON fix: temp file pattern for federated credentials (PowerShell quote mangling)
- Environment consistency: standardize on 'prod' (not 'production') across workflows and credentials
- GitHub Pages fixes: remote_theme, correct baseurl, github-pages gem
- Scanner repo secrets: deploy-all.yml needs OIDC secrets on scanner repo too
- Codespace-first philosophy: all apps runnable locally via docker build/run
- Per-domain OIDC app: avoid 20-credential limit by not sharing across domains
- Updated Bicep template with ACR + Web App for Containers + uniqueString outputs
- Updated deploy workflow template to use az acr build + container deploy pattern
- Added Dockerfile requirements, port conventions, and Run Locally section specs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: agents/domain-scaffolder.agent.md
+70-2Lines changed: 70 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -81,8 +81,10 @@ Generate the complete `{domain}-scan-demo-app` repository structure following th
81
81
8. Create `infra/storage.bicep` for ADLS Gen2 storage.
82
82
9. Create `docs/` with overview, Power BI data model, and workshop setup documentation.
83
83
10. Create `README.md` with project overview.
84
-
11. Generate `.github/workflows/deploy.yml` for each demo app directory. Each deploy workflow MUST include: OIDC login, resource group creation via Bicep, language-specific build step, App Service deployment, health check, and `GITHUB_STEP_SUMMARY` output. Use the per-language deploy workflow template from the scaffolding skill.
85
-
12. Include repository metadata in bootstrap scripts: set topics array, repository description, and enable GitHub Advanced Security code scanning for each demo app repo. Follow the repository metadata conventions from the scaffolding instructions.
84
+
11. Generate `.github/workflows/deploy.yml` for each demo app directory. Each deploy workflow MUST use **containerized deployment**: Docker build → ACR push → Web App for Containers deploy. Include: OIDC login, resource group creation via Bicep, `az acr build`, deploy to Web App for Containers via `azure/webapps-deploy@v3` with `images:` parameter, health check, and `GITHUB_STEP_SUMMARY` output. Use the container deploy workflow template from the scaffolding skill.
85
+
12. All `infra/main.bicep` files MUST use `uniqueString(resourceGroup().id)` for globally-scoped resource names (ACR, App Service, App Service Plan). Bicep MUST provision ACR + Web App for Containers (Linux, Docker), not Oryx code-deploy App Service.
86
+
13. Include repository metadata in bootstrap scripts: set topics array, repository description, enable GitHub Advanced Security code scanning for each demo app repo, and **set OIDC secrets on the scanner repo** in addition to individual app repos. Follow the repository metadata conventions from the scaffolding instructions.
87
+
14. All demo apps MUST be runnable locally in GitHub Codespaces via `docker build -t app . && docker run -p 3000:3000 app` without requiring Azure deployment.
86
88
87
89
### Step 5: Generate Workshop Repository
88
90
@@ -110,6 +112,8 @@ Configure repository-level settings that must be applied after content is pushed
110
112
3. Set **repository description** on both repos using `gh repo edit --description`.
111
113
4. Set **repository topics** on both repos using `gh repo edit --add-topic` for each topic in the domain topics array.
112
114
5. Set the **website URL** on the workshop repo to its GitHub Pages URL.
115
+
6. Set **OIDC secrets** (`AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_SUBSCRIPTION_ID`) on the **scanner repo** — the `deploy-all.yml` runs there.
116
+
7. Create the **`prod` environment** on the scanner repo (not `production` — match the federated credential subject).
113
117
114
118
### Step 7: Produce Summary
115
119
@@ -156,9 +160,73 @@ After scaffolding is complete:
156
160
- Hand off to **CodeQualityDetector** to scan generated sample apps and verify they contain sufficient intentional violations (minimum 15 findings per app).
157
161
- Hand off to **TestGenerator** to generate initial test suites for the sample apps to establish baseline coverage metrics.
158
162
163
+
## Lessons Learned from Prior Iterations
164
+
165
+
Apply these lessons when scaffolding any new domain. These were discovered during the Code Quality domain scaffolding and MUST be codified in all generated artifacts.
166
+
167
+
### 1. Container-First Deployment (Web App for Containers)
168
+
169
+
All 5 demo apps MUST deploy as **Docker containers** to Azure Web App for Containers. Do NOT use Oryx-based source deployment — it fails for Go and is fragile for other languages. The uniform container approach works for all languages and mirrors production patterns.
170
+
171
+
- Every demo app already has a `Dockerfile` — use it as the deployment artifact.
172
+
- Use Azure Container Registry (ACR) to push images, then deploy via `azure/webapps-deploy@v3` with the `images` parameter.
173
+
- The ACR name MUST use Bicep `uniqueString(resourceGroup().id)` for global uniqueness.
174
+
175
+
### 2. Global Uniqueness via Bicep `uniqueString()`
176
+
177
+
Many students run workshops simultaneously. All globally-scoped Azure resource names MUST include `uniqueString(resourceGroup().id)` to avoid collisions:
When passing JSON to Azure CLI from PowerShell, NEVER use inline `ConvertTo-Json -Compress`. PowerShell mangles the quotes. Always write to a temp file and pass `@$tempFile`:
- GitHub environment: `gh api repos/{org}/{repo}/environments/prod --method PUT`
203
+
204
+
### 5. Secrets on Scanner Repo
205
+
206
+
The `deploy-all.yml` workflow runs on the **scanner repo** (`{domain}-scan-demo-app`), not on individual demo app repos. The bootstrap script MUST also set `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_SUBSCRIPTION_ID` on the scanner repo itself, and create the `prod` environment there.
207
+
208
+
### 6. GitHub Pages Configuration
209
+
210
+
For project sites (non-org pages), workshop `_config.yml` MUST:
211
+
212
+
- Set `baseurl: "/{repo-name}"` (not empty string)
213
+
- Use `remote_theme: just-the-docs/just-the-docs` (not `theme: just-the-docs`)
214
+
- Use `github-pages` gem (not `jekyll` gem directly) in the `Gemfile`
215
+
216
+
### 7. Codespace-First Philosophy
217
+
218
+
All demo apps MUST be runnable and testable inside GitHub Codespaces without Azure deployment. Students can always `docker build` and `docker run` locally in a Codespace. Lab instructions SHOULD include a "Run Locally" alternative for each deploy step.
219
+
220
+
### 8. Per-Domain OIDC App Registration
221
+
222
+
Azure AD federated identity credentials have a **maximum of 20 per app**. Do NOT share a single OIDC app across multiple domains. Each domain MUST create its own dedicated app registration (e.g., `code-quality-scan-demo-app-oidc`).
223
+
159
224
## Conventions
160
225
161
226
Follow all conventions defined in `instructions/domain-scaffolding.instructions.md` for naming, SARIF standards, bootstrap scripts, CI/CD pipelines, Power BI PBIP, workshop labs, demo app violations, and screenshot automation.
162
227
163
228
-**PowerShell Only**: All generated commands in screenshot manifests, lab instructions, bootstrap scripts, and CI/CD pipelines MUST use PowerShell Core syntax. Never generate Unix-only commands (`head`, `tail`, `cat`, `2>/dev/null`, `/tmp/`, `./script`).
164
229
-**Idempotent Bootstrap**: All bootstrap scripts MUST be safe to re-run without errors. Every resource creation step MUST check for existing resources before creating.
230
+
-**Container-First**: All demo apps deploy as Docker containers via ACR + Web App for Containers. Never use Oryx source deployment.
231
+
-**Global Uniqueness**: All Azure resource names with global scope MUST use `uniqueString(resourceGroup().id)` in Bicep.
232
+
-**Codespace-Ready**: All demo apps MUST be buildable and runnable in Codespaces via `docker build && docker run`.
@@ -215,25 +215,25 @@ Each sample app directory (`{prefix}-demo-app-001` through `005`) is pushed to i
215
215
216
216
### Deploy Workflow Requirements
217
217
218
+
Every per-app deploy.yml MUST use **containerized deployment** (Web App for Containers). Do NOT use Oryx-based source deployment — it fails for Go and is fragile for other languages. The container approach works identically for all 5 languages and mirrors production deployment patterns.
219
+
218
220
Every per-app deploy.yml MUST include these stages:
| TypeScript | `npm ci && npm run build` | `dist/` or `.next/` directory |
236
-
| Go | `go build -o ./app .` | `./app` binary |
232
+
Language-specific build steps are **no longer needed** in the deploy workflow because all apps are built via `docker build` using their `Dockerfile`. Each demo app MUST include a production-ready `Dockerfile`.
233
+
234
+
### Deploy Workflow Environment Name
235
+
236
+
All deploy workflows MUST use `environment: prod` (not `production`). This MUST match the OIDC federated credential subject: `repo:{org}/{repo}:environment:prod`. Mismatched environment names cause OIDC login failures.
237
237
238
238
### Workflow Permissions
239
239
@@ -243,6 +243,151 @@ permissions:
243
243
contents: read
244
244
```
245
245
246
+
## Global Uniqueness via Bicep `uniqueString()`
247
+
248
+
Many workshop students deploy simultaneously to the same Azure subscription. All globally-scoped Azure resource names MUST include `uniqueString(resourceGroup().id)` in Bicep to avoid naming collisions.
All demo apps MUST be runnable and testable inside GitHub Codespaces without Azure deployment. This provides a zero-cost, zero-config development experience for workshop participants.
324
+
325
+
### Requirements
326
+
327
+
1. Every demo app MUST include a `README.md` section titled "Run Locally" with:
328
+
```bash
329
+
docker build -t {prefix}-demo-app-NNN .
330
+
docker run -p 3000:3000 {prefix}-demo-app-NNN
331
+
```
332
+
2. Workshop lab instructions SHOULD include a "Run Locally in Codespace" alternative for each deploy step
333
+
3. The workshop `.devcontainer/devcontainer.json` MUST include Docker-in-Docker feature for local builds
334
+
335
+
## OIDC Script Conventions
336
+
337
+
### JSON Quoting Fix
338
+
339
+
When passing JSON to Azure CLI from PowerShell, NEVER use inline `ConvertTo-Json -Compress`. PowerShell mangles the quotes when interpolating. Always write to a temp file:
az ad app federated-credential create --id $appId --parameters "@$tempFile"
351
+
Remove-Item -Path $tempFile -Force
352
+
```
353
+
354
+
### Per-Domain OIDC App Registration
355
+
356
+
Azure AD federated identity credentials have a **maximum of 20 per app**. With 6+ repos × 3 subjects (main/dev/prod) = 18+, a shared OIDC app across domains will hit this limit. Each domain MUST create its own dedicated app registration.
357
+
358
+
### Scanner Repo Secrets
359
+
360
+
The `deploy-all.yml` workflow runs on the scanner repo (`{domain}-scan-demo-app`). The OIDC setup and bootstrap scripts MUST also:
361
+
362
+
1. Set `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_SUBSCRIPTION_ID` secrets on the scanner repo
363
+
2. Create the `prod` environment on the scanner repo
364
+
3. Add federated credentials for `repo:{org}/{domain}-scan-demo-app:environment:prod`
365
+
366
+
## GitHub Pages Configuration (Workshop)
367
+
368
+
### Jekyll Config
369
+
370
+
Workshop `_config.yml` MUST use these settings for project sites:
371
+
372
+
```yaml
373
+
remote_theme: just-the-docs/just-the-docs
374
+
baseurl: "/{repo-name}" # MUST be /{repo-name} for project sites, NOT empty string
375
+
url: "https://{org}.github.io"
376
+
```
377
+
378
+
Do NOT use `theme: just-the-docs` — it only works locally. Use `remote_theme` for GitHub Pages compatibility.
379
+
380
+
### Gemfile
381
+
382
+
Workshop `Gemfile` MUST use the `github-pages` gem:
383
+
384
+
```ruby
385
+
source "https://rubygems.org"
386
+
gem "github-pages", group: :jekyll_plugins
387
+
```
388
+
389
+
Do NOT use `gem "jekyll"` or `gem "just-the-docs"` directly — they may not be compatible with GitHub Pages.
390
+
246
391
## Repository Metadata
247
392
248
393
Both generated repositories MUST have metadata configured via bootstrap scripts or repository setup steps.
0 commit comments