@polymorphism-tech/morph-spec 2.4.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +158 -26
- package/LICENSE +72 -72
- package/bin/detect-agents.js +225 -225
- package/bin/morph-spec.js +8 -0
- package/bin/render-template.js +302 -302
- package/bin/semantic-detect-agents.js +246 -246
- package/bin/validate-agents-skills.js +251 -251
- package/bin/validate-agents.js +69 -69
- package/bin/validate-phase.js +263 -263
- package/content/.azure/README.md +293 -293
- package/content/.azure/docs/azure-devops-setup.md +454 -454
- package/content/.azure/docs/branch-strategy.md +398 -398
- package/content/.azure/docs/local-development.md +515 -515
- package/content/.azure/pipelines/pipeline-variables.yml +34 -34
- package/content/.azure/pipelines/prod-pipeline.yml +319 -319
- package/content/.azure/pipelines/staging-pipeline.yml +234 -234
- package/content/.azure/pipelines/templates/build-dotnet.yml +75 -75
- package/content/.azure/pipelines/templates/deploy-app-service.yml +94 -94
- package/content/.azure/pipelines/templates/deploy-container-app.yml +120 -120
- package/content/.azure/pipelines/templates/infra-deploy.yml +90 -90
- package/content/.claude/commands/morph-archive.md +79 -79
- package/content/.claude/commands/morph-deploy.md +529 -0
- package/content/.claude/commands/morph-infra.md +209 -209
- package/content/.claude/commands/morph-preflight.md +227 -227
- package/content/.claude/commands/morph-troubleshoot.md +122 -122
- package/content/.claude/settings.local.json +15 -15
- package/content/.claude/skills/infra/azure-deploy-specialist.md +699 -0
- package/content/.claude/skills/level-0-meta/README.md +7 -0
- package/content/.claude/skills/{checklists → level-0-meta}/morph-checklist.md +117 -117
- package/content/.claude/skills/level-1-workflows/README.md +7 -0
- package/content/.claude/skills/{workflows → level-1-workflows}/morph-replicate.md +213 -213
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-clarify.md +131 -131
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-design.md +213 -205
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-setup.md +106 -92
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-tasks.md +164 -164
- package/content/.claude/skills/{workflows → level-1-workflows}/phase-uiux.md +169 -138
- package/content/.claude/skills/level-2-domains/README.md +14 -0
- package/content/.claude/skills/{specialists → level-2-domains/quality}/testing-specialist.md +126 -126
- package/content/.claude/skills/level-3-technologies/README.md +7 -0
- package/content/.claude/skills/level-4-patterns/README.md +7 -0
- package/content/.claude/skills/specialists/prompt-engineer.md +189 -0
- package/content/.claude/skills/specialists/seo-growth-hacker.md +320 -0
- package/content/.morph/.morphversion +5 -5
- package/content/.morph/archive/.gitkeep +25 -25
- package/content/.morph/config/agents.json +742 -358
- package/content/.morph/config/config.template.json +33 -0
- package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
- package/content/.morph/docs/workflows/enforcement-pipeline.md +668 -0
- package/content/.morph/examples/api-nextjs/README.md +241 -241
- package/content/.morph/examples/api-nextjs/contracts.ts +307 -307
- package/content/.morph/examples/api-nextjs/spec.md +399 -399
- package/content/.morph/examples/api-nextjs/tasks.md +168 -168
- package/content/.morph/examples/micro-saas/README.md +125 -125
- package/content/.morph/examples/micro-saas/contracts.cs +358 -358
- package/content/.morph/examples/micro-saas/decisions.md +246 -246
- package/content/.morph/examples/micro-saas/spec.md +236 -236
- package/content/.morph/examples/micro-saas/tasks.md +150 -150
- package/content/.morph/examples/multi-agent/README.md +309 -309
- package/content/.morph/examples/multi-agent/contracts.cs +433 -433
- package/content/.morph/examples/multi-agent/spec.md +479 -479
- package/content/.morph/examples/multi-agent/tasks.md +185 -185
- package/content/.morph/examples/scheduled-reports/decisions.md +158 -158
- package/content/.morph/examples/scheduled-reports/proposal.md +95 -95
- package/content/.morph/examples/scheduled-reports/spec.md +267 -267
- package/content/.morph/examples/state-v3.json +188 -188
- package/content/.morph/features/.gitkeep +25 -25
- package/content/.morph/hooks/README.md +158 -0
- package/content/.morph/hooks/pre-commit-all.sh +48 -48
- package/content/.morph/hooks/pre-commit-specs.sh +49 -49
- package/content/.morph/hooks/pre-commit-tests.sh +60 -60
- package/content/.morph/hooks/task-completed.js +73 -0
- package/content/.morph/hooks/teammate-idle.js +68 -0
- package/content/.morph/project.md +160 -160
- package/content/.morph/schemas/agent.schema.json +296 -296
- package/content/.morph/schemas/tasks.schema.json +220 -220
- package/content/.morph/specs/.gitkeep +20 -20
- package/content/.morph/standards/agent-teams-workflow.md +474 -0
- package/content/.morph/standards/coding.md +377 -377
- package/content/.morph/standards/fluent-ui-setup.md +590 -590
- package/content/.morph/standards/migration-guide.md +514 -514
- package/content/.morph/standards/passkeys-auth.md +423 -423
- package/content/.morph/standards/vector-search-rag.md +536 -536
- package/content/.morph/state.json +17 -17
- package/content/.morph/templates/CONTEXT-FEATURE.md +276 -0
- package/content/.morph/templates/CONTEXT.md +170 -0
- package/content/.morph/templates/FluentDesignTheme.cs +149 -149
- package/content/.morph/templates/MudTheme.cs +281 -281
- package/content/.morph/templates/clarify-questions.md +159 -159
- package/content/.morph/templates/component.razor +239 -239
- package/content/.morph/templates/contracts/Commands.cs +74 -74
- package/content/.morph/templates/contracts/Entities.cs +25 -25
- package/content/.morph/templates/contracts/Queries.cs +74 -74
- package/content/.morph/templates/contracts/README.md +74 -74
- package/content/.morph/templates/contracts.cs +217 -217
- package/content/.morph/templates/design-system.css +226 -226
- package/content/.morph/templates/infra/.dockerignore.example +89 -89
- package/content/.morph/templates/infra/Dockerfile.example +82 -82
- package/content/.morph/templates/infra/README.md +286 -286
- package/content/.morph/templates/infra/app-insights.bicep +63 -63
- package/content/.morph/templates/infra/app-service.bicep +164 -164
- package/content/.morph/templates/infra/azure-pipelines-deploy.yml +480 -0
- package/content/.morph/templates/infra/container-app-env.bicep +49 -49
- package/content/.morph/templates/infra/container-app.bicep +156 -156
- package/content/.morph/templates/infra/deploy-checklist.md +426 -426
- package/content/.morph/templates/infra/deploy.ps1 +229 -229
- package/content/.morph/templates/infra/deploy.sh +208 -208
- package/content/.morph/templates/infra/key-vault.bicep +91 -91
- package/content/.morph/templates/infra/main.bicep +189 -189
- package/content/.morph/templates/infra/parameters.dev.json +29 -29
- package/content/.morph/templates/infra/parameters.prod.json +29 -29
- package/content/.morph/templates/infra/parameters.staging.json +29 -29
- package/content/.morph/templates/infra/sql-database.bicep +103 -103
- package/content/.morph/templates/infra/storage.bicep +106 -106
- package/content/.morph/templates/integrations/asaas-client.cs +387 -387
- package/content/.morph/templates/integrations/asaas-webhook.cs +351 -351
- package/content/.morph/templates/integrations/azure-identity-config.cs +288 -288
- package/content/.morph/templates/integrations/clerk-config.cs +258 -258
- package/content/.morph/templates/job.cs +171 -171
- package/content/.morph/templates/migration.cs +83 -83
- package/content/.morph/templates/repository.cs +141 -141
- package/content/.morph/templates/saas/subscription.cs +347 -347
- package/content/.morph/templates/saas/tenant.cs +338 -338
- package/content/.morph/templates/service.cs +139 -139
- package/content/.morph/templates/sprint-status.yaml +68 -68
- package/content/.morph/templates/story.md +143 -143
- package/content/.morph/templates/test.cs +239 -239
- package/content/.morph/templates/ui-design-system.md +286 -286
- package/content/.morph/templates/ui-flows.md +336 -336
- package/content/.morph/templates/ui-mockups.md +133 -133
- package/content/.morph/test-infra/example.bicep +59 -59
- package/content/README.md +79 -79
- package/detectors/config-detector.js +223 -223
- package/detectors/conversation-analyzer.js +163 -163
- package/detectors/index.js +84 -84
- package/detectors/standards-generator.js +275 -275
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
- package/docs/api/scripts/collapse.js +38 -38
- package/docs/api/scripts/commonNav.js +28 -28
- package/docs/api/scripts/linenumber.js +25 -25
- package/docs/api/scripts/nav.js +12 -12
- package/docs/api/scripts/polyfill.js +3 -3
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
- package/docs/api/scripts/prettify/lang-css.js +2 -2
- package/docs/api/scripts/prettify/prettify.js +28 -28
- package/docs/api/scripts/search.js +98 -98
- package/docs/api/styles/jsdoc.css +776 -776
- package/docs/api/styles/prettify.css +80 -80
- package/docs/examples.md +328 -328
- package/docs/templates.md +418 -418
- package/package.json +1 -1
- package/scripts/postinstall.js +132 -132
- package/src/commands/advance-phase.js +83 -0
- package/src/commands/analyze-blazor-concurrency.js +193 -193
- package/src/commands/create-story.js +351 -351
- package/src/commands/deploy.js +780 -0
- package/src/commands/detect-agents.js +34 -6
- package/src/commands/detect.js +104 -104
- package/src/commands/generate-context.js +40 -0
- package/src/commands/generate.js +149 -149
- package/src/commands/lint-fluent.js +352 -352
- package/src/commands/rollback-phase.js +185 -185
- package/src/commands/session-summary.js +291 -291
- package/src/commands/shard-spec.js +224 -224
- package/src/commands/sprint-status.js +250 -250
- package/src/commands/state.js +333 -333
- package/src/commands/sync.js +167 -167
- package/src/commands/troubleshoot.js +222 -222
- package/src/commands/validate-blazor-state.js +210 -210
- package/src/commands/validate-blazor.js +156 -156
- package/src/commands/validate-css.js +84 -84
- package/src/commands/validate-phase.js +221 -221
- package/src/lib/blazor-concurrency-analyzer.js +288 -288
- package/src/lib/blazor-state-validator.js +291 -291
- package/src/lib/blazor-validator.js +374 -374
- package/src/lib/context-generator.js +513 -0
- package/src/lib/css-validator.js +352 -352
- package/src/lib/design-system-detector.js +187 -0
- package/src/lib/design-system-generator.js +298 -298
- package/src/lib/design-system-scaffolder.js +299 -0
- package/src/lib/hook-executor.js +256 -0
- package/src/lib/learning-system.js +520 -520
- package/src/lib/mockup-generator.js +366 -366
- package/src/lib/spec-validator.js +258 -0
- package/src/lib/standards-context-injector.js +287 -0
- package/src/lib/team-orchestrator.js +322 -0
- package/src/lib/troubleshoot-grep.js +194 -194
- package/src/lib/troubleshoot-index.js +144 -144
- package/src/lib/ui-detector.js +350 -350
- package/src/lib/validation-runner.js +65 -13
- package/src/lib/validators/architecture-validator.js +387 -387
- package/src/lib/validators/design-system-validator.js +231 -0
- package/src/lib/validators/package-validator.js +360 -360
- package/src/lib/validators/ui-contrast-validator.js +422 -422
- package/src/utils/file-copier.js +9 -1
- package/src/utils/logger.js +32 -32
- package/src/utils/version-checker.js +175 -175
- /package/content/.claude/skills/{checklists → level-0-meta}/code-review.md +0 -0
- /package/content/.claude/skills/{checklists → level-0-meta}/simulation-checklist.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/ai-agents}/ai-system-architect.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/architecture}/po-pm-advisor.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/architecture}/standards-architect.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/dotnet-senior.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/ef-modeler.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/hangfire-orchestrator.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/backend}/ms-agent-expert.md +0 -0
- /package/content/.claude/skills/{stacks/dotnet-blazor.md → level-2-domains/frontend/blazor-builder.md} +0 -0
- /package/content/.claude/skills/{stacks/dotnet-nextjs.md → level-2-domains/frontend/nextjs-expert.md} +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/frontend}/ui-ux-designer.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/infrastructure}/azure-architect.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/bicep-architect.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/container-specialist.md +0 -0
- /package/content/.claude/skills/{infra → level-2-domains/infrastructure}/devops-engineer.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/asaas-financial.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/azure-identity.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/clerk-auth.md +0 -0
- /package/content/.claude/skills/{integrations → level-2-domains/integrations}/resend-email.md +0 -0
- /package/content/.claude/skills/{specialists → level-2-domains/quality}/code-analyzer.md +0 -0
|
@@ -1,319 +1,319 @@
|
|
|
1
|
-
# ==============================================================================
|
|
2
|
-
# MORPH-SPEC - Production Pipeline
|
|
3
|
-
# Deployment to Azure Container Apps with manual approval and always-on
|
|
4
|
-
# ==============================================================================
|
|
5
|
-
|
|
6
|
-
trigger:
|
|
7
|
-
branches:
|
|
8
|
-
include:
|
|
9
|
-
- main
|
|
10
|
-
- master
|
|
11
|
-
|
|
12
|
-
pr: none # No PR builds for prod
|
|
13
|
-
|
|
14
|
-
variables:
|
|
15
|
-
- template: pipeline-variables.yml
|
|
16
|
-
- name: environment
|
|
17
|
-
value: 'prod'
|
|
18
|
-
- name: resourceGroupName
|
|
19
|
-
value: 'rg-$(APP_NAME)-prod'
|
|
20
|
-
- name: containerAppName
|
|
21
|
-
value: 'ca-$(APP_NAME)-prod'
|
|
22
|
-
- name: hostingType
|
|
23
|
-
value: 'containerapp'
|
|
24
|
-
- name: parametersFile
|
|
25
|
-
value: 'content/.morph/templates/infra/parameters.prod.json'
|
|
26
|
-
- name: imageName
|
|
27
|
-
value: '$(APP_NAME)'
|
|
28
|
-
- name: imageFullName
|
|
29
|
-
value: '$(containerRegistry)/$(imageName):$(imageTag)'
|
|
30
|
-
|
|
31
|
-
stages:
|
|
32
|
-
# ===========================================================================
|
|
33
|
-
# STAGE 1: Build & Test
|
|
34
|
-
# ===========================================================================
|
|
35
|
-
- stage: Build
|
|
36
|
-
displayName: 'Build & Test'
|
|
37
|
-
jobs:
|
|
38
|
-
- job: BuildJob
|
|
39
|
-
displayName: 'Build .NET Application'
|
|
40
|
-
pool:
|
|
41
|
-
vmImage: 'ubuntu-latest'
|
|
42
|
-
steps:
|
|
43
|
-
- checkout: self
|
|
44
|
-
fetchDepth: 1
|
|
45
|
-
|
|
46
|
-
- template: templates/build-dotnet.yml
|
|
47
|
-
parameters:
|
|
48
|
-
dotnetVersion: $(dotnetVersion)
|
|
49
|
-
buildConfiguration: $(buildConfiguration)
|
|
50
|
-
runTests: true
|
|
51
|
-
publishArtifact: false
|
|
52
|
-
|
|
53
|
-
# ===========================================================================
|
|
54
|
-
# STAGE 2: Security Scan
|
|
55
|
-
# ===========================================================================
|
|
56
|
-
- stage: SecurityScan
|
|
57
|
-
displayName: 'Security Scan'
|
|
58
|
-
dependsOn: Build
|
|
59
|
-
condition: succeeded()
|
|
60
|
-
jobs:
|
|
61
|
-
- job: SecurityScanJob
|
|
62
|
-
displayName: 'Run Security Scans'
|
|
63
|
-
pool:
|
|
64
|
-
vmImage: 'ubuntu-latest'
|
|
65
|
-
steps:
|
|
66
|
-
- checkout: self
|
|
67
|
-
fetchDepth: 1
|
|
68
|
-
|
|
69
|
-
- task: DotNetCoreCLI@2
|
|
70
|
-
displayName: 'Restore packages'
|
|
71
|
-
inputs:
|
|
72
|
-
command: 'restore'
|
|
73
|
-
|
|
74
|
-
- task: PowerShell@2
|
|
75
|
-
displayName: 'Check for vulnerable packages'
|
|
76
|
-
inputs:
|
|
77
|
-
targetType: 'inline'
|
|
78
|
-
script: |
|
|
79
|
-
Write-Host "🔍 Scanning for vulnerable NuGet packages..."
|
|
80
|
-
dotnet list package --vulnerable --include-transitive
|
|
81
|
-
|
|
82
|
-
if ($LASTEXITCODE -ne 0) {
|
|
83
|
-
Write-Warning "⚠️ Vulnerable packages found. Review before deploying to production."
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
# ===========================================================================
|
|
87
|
-
# STAGE 3: Deploy Infrastructure
|
|
88
|
-
# ===========================================================================
|
|
89
|
-
- stage: DeployInfra
|
|
90
|
-
displayName: 'Deploy Infrastructure'
|
|
91
|
-
dependsOn: SecurityScan
|
|
92
|
-
condition: succeeded()
|
|
93
|
-
jobs:
|
|
94
|
-
- deployment: DeployInfraJob
|
|
95
|
-
displayName: 'Deploy Bicep Templates'
|
|
96
|
-
pool:
|
|
97
|
-
vmImage: 'ubuntu-latest'
|
|
98
|
-
environment: 'production' # Requires manual approval in Azure DevOps
|
|
99
|
-
strategy:
|
|
100
|
-
runOnce:
|
|
101
|
-
deploy:
|
|
102
|
-
steps:
|
|
103
|
-
- checkout: self
|
|
104
|
-
fetchDepth: 1
|
|
105
|
-
|
|
106
|
-
- template: templates/infra-deploy.yml
|
|
107
|
-
parameters:
|
|
108
|
-
azureSubscription: 'Azure-Prod-Connection'
|
|
109
|
-
resourceGroupName: $(resourceGroupName)
|
|
110
|
-
location: $(azureLocation)
|
|
111
|
-
environment: $(environment)
|
|
112
|
-
appName: $(APP_NAME)
|
|
113
|
-
hostingType: $(hostingType)
|
|
114
|
-
bicepTemplateFile: $(bicepTemplateFile)
|
|
115
|
-
parametersFile: $(parametersFile)
|
|
116
|
-
|
|
117
|
-
# ===========================================================================
|
|
118
|
-
# STAGE 4: Build and Push Container
|
|
119
|
-
# ===========================================================================
|
|
120
|
-
- stage: BuildContainer
|
|
121
|
-
displayName: 'Build Container'
|
|
122
|
-
dependsOn: DeployInfra
|
|
123
|
-
condition: succeeded()
|
|
124
|
-
jobs:
|
|
125
|
-
- job: BuildContainerJob
|
|
126
|
-
displayName: 'Build and Push Docker Image'
|
|
127
|
-
pool:
|
|
128
|
-
vmImage: 'ubuntu-latest'
|
|
129
|
-
steps:
|
|
130
|
-
- checkout: self
|
|
131
|
-
fetchDepth: 1
|
|
132
|
-
|
|
133
|
-
- task: Docker@2
|
|
134
|
-
displayName: 'Build and push container'
|
|
135
|
-
inputs:
|
|
136
|
-
containerRegistry: 'ACR-Connection'
|
|
137
|
-
repository: '$(imageName)'
|
|
138
|
-
command: 'buildAndPush'
|
|
139
|
-
Dockerfile: '$(dockerfilePath)'
|
|
140
|
-
tags: |
|
|
141
|
-
$(imageTag)
|
|
142
|
-
prod-latest
|
|
143
|
-
$(Build.BuildId)
|
|
144
|
-
|
|
145
|
-
- task: AzureCLI@2
|
|
146
|
-
displayName: 'Scan image for vulnerabilities (Microsoft Defender)'
|
|
147
|
-
continueOnError: false # Fail on vulnerabilities in prod
|
|
148
|
-
inputs:
|
|
149
|
-
azureSubscription: 'Azure-Prod-Connection'
|
|
150
|
-
scriptType: 'bash'
|
|
151
|
-
scriptLocation: 'inlineScript'
|
|
152
|
-
inlineScript: |
|
|
153
|
-
echo "🔍 Scanning image for vulnerabilities..."
|
|
154
|
-
# Add your security scanning tool here (e.g., Trivy, Defender for Containers)
|
|
155
|
-
# az acr scan --name $(ACR_NAME) --image $(imageName):$(imageTag)
|
|
156
|
-
|
|
157
|
-
# ===========================================================================
|
|
158
|
-
# STAGE 5: Deploy to Production (Blue-Green)
|
|
159
|
-
# ===========================================================================
|
|
160
|
-
- stage: DeployApp
|
|
161
|
-
displayName: 'Deploy to Production'
|
|
162
|
-
dependsOn: BuildContainer
|
|
163
|
-
condition: succeeded()
|
|
164
|
-
jobs:
|
|
165
|
-
- deployment: DeployAppJob
|
|
166
|
-
displayName: 'Deploy Container App'
|
|
167
|
-
pool:
|
|
168
|
-
vmImage: 'ubuntu-latest'
|
|
169
|
-
environment: 'production' # Requires manual approval
|
|
170
|
-
strategy:
|
|
171
|
-
runOnce:
|
|
172
|
-
deploy:
|
|
173
|
-
steps:
|
|
174
|
-
- checkout: self
|
|
175
|
-
fetchDepth: 1
|
|
176
|
-
|
|
177
|
-
# Create new revision
|
|
178
|
-
- template: templates/deploy-container-app.yml
|
|
179
|
-
parameters:
|
|
180
|
-
azureSubscription: 'Azure-Prod-Connection'
|
|
181
|
-
containerAppName: $(containerAppName)
|
|
182
|
-
resourceGroupName: $(resourceGroupName)
|
|
183
|
-
containerRegistry: $(containerRegistry)
|
|
184
|
-
imageName: $(imageName)
|
|
185
|
-
imageTag: $(imageTag)
|
|
186
|
-
acrServiceConnection: 'ACR-Connection'
|
|
187
|
-
healthCheckUrl: '/health'
|
|
188
|
-
healthCheckTimeout: 300
|
|
189
|
-
|
|
190
|
-
# Wait before activating
|
|
191
|
-
- task: PowerShell@2
|
|
192
|
-
displayName: 'Monitor new revision (5 min)'
|
|
193
|
-
inputs:
|
|
194
|
-
targetType: 'inline'
|
|
195
|
-
script: |
|
|
196
|
-
Write-Host "⏳ Monitoring new revision for 5 minutes before activating..."
|
|
197
|
-
Start-Sleep -Seconds 300
|
|
198
|
-
Write-Host "✅ Monitoring period complete"
|
|
199
|
-
|
|
200
|
-
# ===========================================================================
|
|
201
|
-
# STAGE 6: Smoke Tests in Production
|
|
202
|
-
# ===========================================================================
|
|
203
|
-
- stage: SmokeTests
|
|
204
|
-
displayName: 'Production Smoke Tests'
|
|
205
|
-
dependsOn: DeployApp
|
|
206
|
-
condition: succeeded()
|
|
207
|
-
jobs:
|
|
208
|
-
- job: SmokeTestsJob
|
|
209
|
-
displayName: 'Run Production Smoke Tests'
|
|
210
|
-
pool:
|
|
211
|
-
vmImage: 'ubuntu-latest'
|
|
212
|
-
steps:
|
|
213
|
-
- task: AzureCLI@2
|
|
214
|
-
displayName: 'Get Container App URL'
|
|
215
|
-
name: getUrl
|
|
216
|
-
inputs:
|
|
217
|
-
azureSubscription: 'Azure-Prod-Connection'
|
|
218
|
-
scriptType: 'bash'
|
|
219
|
-
scriptLocation: 'inlineScript'
|
|
220
|
-
inlineScript: |
|
|
221
|
-
FQDN=$(az containerapp show \
|
|
222
|
-
--name $(containerAppName) \
|
|
223
|
-
--resource-group $(resourceGroupName) \
|
|
224
|
-
--query properties.configuration.ingress.fqdn -o tsv)
|
|
225
|
-
|
|
226
|
-
APP_URL="https://$FQDN"
|
|
227
|
-
echo "##vso[task.setvariable variable=appUrl]$APP_URL"
|
|
228
|
-
echo "Production URL: $APP_URL"
|
|
229
|
-
|
|
230
|
-
- task: PowerShell@2
|
|
231
|
-
displayName: 'Critical smoke tests'
|
|
232
|
-
inputs:
|
|
233
|
-
targetType: 'inline'
|
|
234
|
-
script: |
|
|
235
|
-
$appUrl = "$(appUrl)"
|
|
236
|
-
|
|
237
|
-
Write-Host "🧪 Running CRITICAL smoke tests in PRODUCTION"
|
|
238
|
-
Write-Host "URL: $appUrl"
|
|
239
|
-
|
|
240
|
-
$criticalEndpoints = @(
|
|
241
|
-
@{Path="/health"; Description="Health Check"},
|
|
242
|
-
@{Path="/health/ready"; Description="Readiness Check"},
|
|
243
|
-
@{Path="/"; Description="Home Page"}
|
|
244
|
-
)
|
|
245
|
-
|
|
246
|
-
$failed = $false
|
|
247
|
-
foreach ($endpoint in $criticalEndpoints) {
|
|
248
|
-
$url = "$appUrl$($endpoint.Path)"
|
|
249
|
-
try {
|
|
250
|
-
$response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10
|
|
251
|
-
Write-Host "✅ $($endpoint.Description): $($response.StatusCode)"
|
|
252
|
-
}
|
|
253
|
-
catch {
|
|
254
|
-
Write-Error "❌ $($endpoint.Description) FAILED: $_"
|
|
255
|
-
$failed = $true
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if ($failed) {
|
|
260
|
-
Write-Error "❌ CRITICAL: Smoke tests failed in production!"
|
|
261
|
-
exit 1
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
Write-Host "✅ All critical smoke tests passed!"
|
|
265
|
-
|
|
266
|
-
- task: AzureCLI@2
|
|
267
|
-
displayName: 'Monitor metrics'
|
|
268
|
-
inputs:
|
|
269
|
-
azureSubscription: 'Azure-Prod-Connection'
|
|
270
|
-
scriptType: 'bash'
|
|
271
|
-
scriptLocation: 'inlineScript'
|
|
272
|
-
inlineScript: |
|
|
273
|
-
echo "📊 Production Deployment Metrics:"
|
|
274
|
-
|
|
275
|
-
# Get replica count
|
|
276
|
-
REPLICAS=$(az containerapp revision list \
|
|
277
|
-
--name $(containerAppName) \
|
|
278
|
-
--resource-group $(resourceGroupName) \
|
|
279
|
-
--query "[?properties.active].properties.replicas" -o tsv)
|
|
280
|
-
|
|
281
|
-
echo "Active Replicas: $REPLICAS"
|
|
282
|
-
|
|
283
|
-
# Show active revisions
|
|
284
|
-
az containerapp revision list \
|
|
285
|
-
--name $(containerAppName) \
|
|
286
|
-
--resource-group $(resourceGroupName) \
|
|
287
|
-
--query "[?properties.active].{Name:name, Traffic:properties.trafficWeight, Replicas:properties.replicas}" \
|
|
288
|
-
--output table
|
|
289
|
-
|
|
290
|
-
- task: AzureCLI@2
|
|
291
|
-
displayName: 'Deployment summary'
|
|
292
|
-
inputs:
|
|
293
|
-
azureSubscription: 'Azure-Prod-Connection'
|
|
294
|
-
scriptType: 'bash'
|
|
295
|
-
scriptLocation: 'inlineScript'
|
|
296
|
-
inlineScript: |
|
|
297
|
-
echo "╔════════════════════════════════════════════════════════════════╗"
|
|
298
|
-
echo "║ PRODUCTION DEPLOYMENT SUCCESSFUL ║"
|
|
299
|
-
echo "╚════════════════════════════════════════════════════════════════╝"
|
|
300
|
-
echo ""
|
|
301
|
-
echo "🌐 Application URL: $(appUrl)"
|
|
302
|
-
echo "📊 Environment: $(environment)"
|
|
303
|
-
echo "🐳 Container Image: $(imageFullName)"
|
|
304
|
-
echo "💰 Hosting: Container Apps (always-on) - ~$10-20/month"
|
|
305
|
-
echo "📦 Resource Group: $(resourceGroupName)"
|
|
306
|
-
echo "🏷️ Version: $(imageTag)"
|
|
307
|
-
echo ""
|
|
308
|
-
echo "⚠️ IMPORTANT:"
|
|
309
|
-
echo " 1. Monitor Application Insights for errors"
|
|
310
|
-
echo " 2. Watch for performance degradation"
|
|
311
|
-
echo " 3. Have rollback plan ready"
|
|
312
|
-
echo " 4. Monitor costs in Azure Portal"
|
|
313
|
-
echo ""
|
|
314
|
-
echo "🔄 Rollback command (if needed):"
|
|
315
|
-
echo " az containerapp revision activate \\"
|
|
316
|
-
echo " --name $(containerAppName) \\"
|
|
317
|
-
echo " --resource-group $(resourceGroupName) \\"
|
|
318
|
-
echo " --revision <PREVIOUS_REVISION_NAME>"
|
|
319
|
-
echo ""
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# MORPH-SPEC - Production Pipeline
|
|
3
|
+
# Deployment to Azure Container Apps with manual approval and always-on
|
|
4
|
+
# ==============================================================================
|
|
5
|
+
|
|
6
|
+
trigger:
|
|
7
|
+
branches:
|
|
8
|
+
include:
|
|
9
|
+
- main
|
|
10
|
+
- master
|
|
11
|
+
|
|
12
|
+
pr: none # No PR builds for prod
|
|
13
|
+
|
|
14
|
+
variables:
|
|
15
|
+
- template: pipeline-variables.yml
|
|
16
|
+
- name: environment
|
|
17
|
+
value: 'prod'
|
|
18
|
+
- name: resourceGroupName
|
|
19
|
+
value: 'rg-$(APP_NAME)-prod'
|
|
20
|
+
- name: containerAppName
|
|
21
|
+
value: 'ca-$(APP_NAME)-prod'
|
|
22
|
+
- name: hostingType
|
|
23
|
+
value: 'containerapp'
|
|
24
|
+
- name: parametersFile
|
|
25
|
+
value: 'content/.morph/templates/infra/parameters.prod.json'
|
|
26
|
+
- name: imageName
|
|
27
|
+
value: '$(APP_NAME)'
|
|
28
|
+
- name: imageFullName
|
|
29
|
+
value: '$(containerRegistry)/$(imageName):$(imageTag)'
|
|
30
|
+
|
|
31
|
+
stages:
|
|
32
|
+
# ===========================================================================
|
|
33
|
+
# STAGE 1: Build & Test
|
|
34
|
+
# ===========================================================================
|
|
35
|
+
- stage: Build
|
|
36
|
+
displayName: 'Build & Test'
|
|
37
|
+
jobs:
|
|
38
|
+
- job: BuildJob
|
|
39
|
+
displayName: 'Build .NET Application'
|
|
40
|
+
pool:
|
|
41
|
+
vmImage: 'ubuntu-latest'
|
|
42
|
+
steps:
|
|
43
|
+
- checkout: self
|
|
44
|
+
fetchDepth: 1
|
|
45
|
+
|
|
46
|
+
- template: templates/build-dotnet.yml
|
|
47
|
+
parameters:
|
|
48
|
+
dotnetVersion: $(dotnetVersion)
|
|
49
|
+
buildConfiguration: $(buildConfiguration)
|
|
50
|
+
runTests: true
|
|
51
|
+
publishArtifact: false
|
|
52
|
+
|
|
53
|
+
# ===========================================================================
|
|
54
|
+
# STAGE 2: Security Scan
|
|
55
|
+
# ===========================================================================
|
|
56
|
+
- stage: SecurityScan
|
|
57
|
+
displayName: 'Security Scan'
|
|
58
|
+
dependsOn: Build
|
|
59
|
+
condition: succeeded()
|
|
60
|
+
jobs:
|
|
61
|
+
- job: SecurityScanJob
|
|
62
|
+
displayName: 'Run Security Scans'
|
|
63
|
+
pool:
|
|
64
|
+
vmImage: 'ubuntu-latest'
|
|
65
|
+
steps:
|
|
66
|
+
- checkout: self
|
|
67
|
+
fetchDepth: 1
|
|
68
|
+
|
|
69
|
+
- task: DotNetCoreCLI@2
|
|
70
|
+
displayName: 'Restore packages'
|
|
71
|
+
inputs:
|
|
72
|
+
command: 'restore'
|
|
73
|
+
|
|
74
|
+
- task: PowerShell@2
|
|
75
|
+
displayName: 'Check for vulnerable packages'
|
|
76
|
+
inputs:
|
|
77
|
+
targetType: 'inline'
|
|
78
|
+
script: |
|
|
79
|
+
Write-Host "🔍 Scanning for vulnerable NuGet packages..."
|
|
80
|
+
dotnet list package --vulnerable --include-transitive
|
|
81
|
+
|
|
82
|
+
if ($LASTEXITCODE -ne 0) {
|
|
83
|
+
Write-Warning "⚠️ Vulnerable packages found. Review before deploying to production."
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# ===========================================================================
|
|
87
|
+
# STAGE 3: Deploy Infrastructure
|
|
88
|
+
# ===========================================================================
|
|
89
|
+
- stage: DeployInfra
|
|
90
|
+
displayName: 'Deploy Infrastructure'
|
|
91
|
+
dependsOn: SecurityScan
|
|
92
|
+
condition: succeeded()
|
|
93
|
+
jobs:
|
|
94
|
+
- deployment: DeployInfraJob
|
|
95
|
+
displayName: 'Deploy Bicep Templates'
|
|
96
|
+
pool:
|
|
97
|
+
vmImage: 'ubuntu-latest'
|
|
98
|
+
environment: 'production' # Requires manual approval in Azure DevOps
|
|
99
|
+
strategy:
|
|
100
|
+
runOnce:
|
|
101
|
+
deploy:
|
|
102
|
+
steps:
|
|
103
|
+
- checkout: self
|
|
104
|
+
fetchDepth: 1
|
|
105
|
+
|
|
106
|
+
- template: templates/infra-deploy.yml
|
|
107
|
+
parameters:
|
|
108
|
+
azureSubscription: 'Azure-Prod-Connection'
|
|
109
|
+
resourceGroupName: $(resourceGroupName)
|
|
110
|
+
location: $(azureLocation)
|
|
111
|
+
environment: $(environment)
|
|
112
|
+
appName: $(APP_NAME)
|
|
113
|
+
hostingType: $(hostingType)
|
|
114
|
+
bicepTemplateFile: $(bicepTemplateFile)
|
|
115
|
+
parametersFile: $(parametersFile)
|
|
116
|
+
|
|
117
|
+
# ===========================================================================
|
|
118
|
+
# STAGE 4: Build and Push Container
|
|
119
|
+
# ===========================================================================
|
|
120
|
+
- stage: BuildContainer
|
|
121
|
+
displayName: 'Build Container'
|
|
122
|
+
dependsOn: DeployInfra
|
|
123
|
+
condition: succeeded()
|
|
124
|
+
jobs:
|
|
125
|
+
- job: BuildContainerJob
|
|
126
|
+
displayName: 'Build and Push Docker Image'
|
|
127
|
+
pool:
|
|
128
|
+
vmImage: 'ubuntu-latest'
|
|
129
|
+
steps:
|
|
130
|
+
- checkout: self
|
|
131
|
+
fetchDepth: 1
|
|
132
|
+
|
|
133
|
+
- task: Docker@2
|
|
134
|
+
displayName: 'Build and push container'
|
|
135
|
+
inputs:
|
|
136
|
+
containerRegistry: 'ACR-Connection'
|
|
137
|
+
repository: '$(imageName)'
|
|
138
|
+
command: 'buildAndPush'
|
|
139
|
+
Dockerfile: '$(dockerfilePath)'
|
|
140
|
+
tags: |
|
|
141
|
+
$(imageTag)
|
|
142
|
+
prod-latest
|
|
143
|
+
$(Build.BuildId)
|
|
144
|
+
|
|
145
|
+
- task: AzureCLI@2
|
|
146
|
+
displayName: 'Scan image for vulnerabilities (Microsoft Defender)'
|
|
147
|
+
continueOnError: false # Fail on vulnerabilities in prod
|
|
148
|
+
inputs:
|
|
149
|
+
azureSubscription: 'Azure-Prod-Connection'
|
|
150
|
+
scriptType: 'bash'
|
|
151
|
+
scriptLocation: 'inlineScript'
|
|
152
|
+
inlineScript: |
|
|
153
|
+
echo "🔍 Scanning image for vulnerabilities..."
|
|
154
|
+
# Add your security scanning tool here (e.g., Trivy, Defender for Containers)
|
|
155
|
+
# az acr scan --name $(ACR_NAME) --image $(imageName):$(imageTag)
|
|
156
|
+
|
|
157
|
+
# ===========================================================================
|
|
158
|
+
# STAGE 5: Deploy to Production (Blue-Green)
|
|
159
|
+
# ===========================================================================
|
|
160
|
+
- stage: DeployApp
|
|
161
|
+
displayName: 'Deploy to Production'
|
|
162
|
+
dependsOn: BuildContainer
|
|
163
|
+
condition: succeeded()
|
|
164
|
+
jobs:
|
|
165
|
+
- deployment: DeployAppJob
|
|
166
|
+
displayName: 'Deploy Container App'
|
|
167
|
+
pool:
|
|
168
|
+
vmImage: 'ubuntu-latest'
|
|
169
|
+
environment: 'production' # Requires manual approval
|
|
170
|
+
strategy:
|
|
171
|
+
runOnce:
|
|
172
|
+
deploy:
|
|
173
|
+
steps:
|
|
174
|
+
- checkout: self
|
|
175
|
+
fetchDepth: 1
|
|
176
|
+
|
|
177
|
+
# Create new revision
|
|
178
|
+
- template: templates/deploy-container-app.yml
|
|
179
|
+
parameters:
|
|
180
|
+
azureSubscription: 'Azure-Prod-Connection'
|
|
181
|
+
containerAppName: $(containerAppName)
|
|
182
|
+
resourceGroupName: $(resourceGroupName)
|
|
183
|
+
containerRegistry: $(containerRegistry)
|
|
184
|
+
imageName: $(imageName)
|
|
185
|
+
imageTag: $(imageTag)
|
|
186
|
+
acrServiceConnection: 'ACR-Connection'
|
|
187
|
+
healthCheckUrl: '/health'
|
|
188
|
+
healthCheckTimeout: 300
|
|
189
|
+
|
|
190
|
+
# Wait before activating
|
|
191
|
+
- task: PowerShell@2
|
|
192
|
+
displayName: 'Monitor new revision (5 min)'
|
|
193
|
+
inputs:
|
|
194
|
+
targetType: 'inline'
|
|
195
|
+
script: |
|
|
196
|
+
Write-Host "⏳ Monitoring new revision for 5 minutes before activating..."
|
|
197
|
+
Start-Sleep -Seconds 300
|
|
198
|
+
Write-Host "✅ Monitoring period complete"
|
|
199
|
+
|
|
200
|
+
# ===========================================================================
|
|
201
|
+
# STAGE 6: Smoke Tests in Production
|
|
202
|
+
# ===========================================================================
|
|
203
|
+
- stage: SmokeTests
|
|
204
|
+
displayName: 'Production Smoke Tests'
|
|
205
|
+
dependsOn: DeployApp
|
|
206
|
+
condition: succeeded()
|
|
207
|
+
jobs:
|
|
208
|
+
- job: SmokeTestsJob
|
|
209
|
+
displayName: 'Run Production Smoke Tests'
|
|
210
|
+
pool:
|
|
211
|
+
vmImage: 'ubuntu-latest'
|
|
212
|
+
steps:
|
|
213
|
+
- task: AzureCLI@2
|
|
214
|
+
displayName: 'Get Container App URL'
|
|
215
|
+
name: getUrl
|
|
216
|
+
inputs:
|
|
217
|
+
azureSubscription: 'Azure-Prod-Connection'
|
|
218
|
+
scriptType: 'bash'
|
|
219
|
+
scriptLocation: 'inlineScript'
|
|
220
|
+
inlineScript: |
|
|
221
|
+
FQDN=$(az containerapp show \
|
|
222
|
+
--name $(containerAppName) \
|
|
223
|
+
--resource-group $(resourceGroupName) \
|
|
224
|
+
--query properties.configuration.ingress.fqdn -o tsv)
|
|
225
|
+
|
|
226
|
+
APP_URL="https://$FQDN"
|
|
227
|
+
echo "##vso[task.setvariable variable=appUrl]$APP_URL"
|
|
228
|
+
echo "Production URL: $APP_URL"
|
|
229
|
+
|
|
230
|
+
- task: PowerShell@2
|
|
231
|
+
displayName: 'Critical smoke tests'
|
|
232
|
+
inputs:
|
|
233
|
+
targetType: 'inline'
|
|
234
|
+
script: |
|
|
235
|
+
$appUrl = "$(appUrl)"
|
|
236
|
+
|
|
237
|
+
Write-Host "🧪 Running CRITICAL smoke tests in PRODUCTION"
|
|
238
|
+
Write-Host "URL: $appUrl"
|
|
239
|
+
|
|
240
|
+
$criticalEndpoints = @(
|
|
241
|
+
@{Path="/health"; Description="Health Check"},
|
|
242
|
+
@{Path="/health/ready"; Description="Readiness Check"},
|
|
243
|
+
@{Path="/"; Description="Home Page"}
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
$failed = $false
|
|
247
|
+
foreach ($endpoint in $criticalEndpoints) {
|
|
248
|
+
$url = "$appUrl$($endpoint.Path)"
|
|
249
|
+
try {
|
|
250
|
+
$response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10
|
|
251
|
+
Write-Host "✅ $($endpoint.Description): $($response.StatusCode)"
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
Write-Error "❌ $($endpoint.Description) FAILED: $_"
|
|
255
|
+
$failed = $true
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if ($failed) {
|
|
260
|
+
Write-Error "❌ CRITICAL: Smoke tests failed in production!"
|
|
261
|
+
exit 1
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
Write-Host "✅ All critical smoke tests passed!"
|
|
265
|
+
|
|
266
|
+
- task: AzureCLI@2
|
|
267
|
+
displayName: 'Monitor metrics'
|
|
268
|
+
inputs:
|
|
269
|
+
azureSubscription: 'Azure-Prod-Connection'
|
|
270
|
+
scriptType: 'bash'
|
|
271
|
+
scriptLocation: 'inlineScript'
|
|
272
|
+
inlineScript: |
|
|
273
|
+
echo "📊 Production Deployment Metrics:"
|
|
274
|
+
|
|
275
|
+
# Get replica count
|
|
276
|
+
REPLICAS=$(az containerapp revision list \
|
|
277
|
+
--name $(containerAppName) \
|
|
278
|
+
--resource-group $(resourceGroupName) \
|
|
279
|
+
--query "[?properties.active].properties.replicas" -o tsv)
|
|
280
|
+
|
|
281
|
+
echo "Active Replicas: $REPLICAS"
|
|
282
|
+
|
|
283
|
+
# Show active revisions
|
|
284
|
+
az containerapp revision list \
|
|
285
|
+
--name $(containerAppName) \
|
|
286
|
+
--resource-group $(resourceGroupName) \
|
|
287
|
+
--query "[?properties.active].{Name:name, Traffic:properties.trafficWeight, Replicas:properties.replicas}" \
|
|
288
|
+
--output table
|
|
289
|
+
|
|
290
|
+
- task: AzureCLI@2
|
|
291
|
+
displayName: 'Deployment summary'
|
|
292
|
+
inputs:
|
|
293
|
+
azureSubscription: 'Azure-Prod-Connection'
|
|
294
|
+
scriptType: 'bash'
|
|
295
|
+
scriptLocation: 'inlineScript'
|
|
296
|
+
inlineScript: |
|
|
297
|
+
echo "╔════════════════════════════════════════════════════════════════╗"
|
|
298
|
+
echo "║ PRODUCTION DEPLOYMENT SUCCESSFUL ║"
|
|
299
|
+
echo "╚════════════════════════════════════════════════════════════════╝"
|
|
300
|
+
echo ""
|
|
301
|
+
echo "🌐 Application URL: $(appUrl)"
|
|
302
|
+
echo "📊 Environment: $(environment)"
|
|
303
|
+
echo "🐳 Container Image: $(imageFullName)"
|
|
304
|
+
echo "💰 Hosting: Container Apps (always-on) - ~$10-20/month"
|
|
305
|
+
echo "📦 Resource Group: $(resourceGroupName)"
|
|
306
|
+
echo "🏷️ Version: $(imageTag)"
|
|
307
|
+
echo ""
|
|
308
|
+
echo "⚠️ IMPORTANT:"
|
|
309
|
+
echo " 1. Monitor Application Insights for errors"
|
|
310
|
+
echo " 2. Watch for performance degradation"
|
|
311
|
+
echo " 3. Have rollback plan ready"
|
|
312
|
+
echo " 4. Monitor costs in Azure Portal"
|
|
313
|
+
echo ""
|
|
314
|
+
echo "🔄 Rollback command (if needed):"
|
|
315
|
+
echo " az containerapp revision activate \\"
|
|
316
|
+
echo " --name $(containerAppName) \\"
|
|
317
|
+
echo " --resource-group $(resourceGroupName) \\"
|
|
318
|
+
echo " --revision <PREVIOUS_REVISION_NAME>"
|
|
319
|
+
echo ""
|