Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 97 additions & 24 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ on:
push:
tags:
- "v*.*.*"
workflow_dispatch:
inputs:
prerelease_suffix:
description: "Optional prerelease suffix (example: rc.1). If empty, branch.run_number is used"
required: false
type: string

env:
REGISTRY: ghcr.io
Expand All @@ -18,6 +24,10 @@ jobs:

outputs:
version: ${{ steps.version.outputs.value }}
base_version: ${{ steps.version.outputs.base_value }}
image_tag: ${{ steps.version.outputs.image_tag }}
prerelease: ${{ steps.version.outputs.prerelease }}
tag_name: ${{ steps.version.outputs.tag_name }}

strategy:
fail-fast: false
Expand All @@ -36,12 +46,37 @@ jobs:
id: version
run: |
VERSION=$(cat VERSION | tr -d '[:space:]')
TAG="${GITHUB_REF_NAME}"
if [ "$VERSION" != "$TAG" ]; then
echo "::error::VERSION file ($VERSION) does not match git tag ($TAG)"
exit 1

if [ "${{ github.event_name }}" = "push" ]; then
TAG="${GITHUB_REF_NAME}"
if [ "$VERSION" != "$TAG" ]; then
echo "::error::VERSION file ($VERSION) does not match git tag ($TAG)"
exit 1
fi

RELEASE_VERSION="$VERSION"
RELEASE_TAG="$TAG"
PRERELEASE="false"
else
BRANCH=$(echo "${GITHUB_REF_NAME}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//')
SUFFIX="${{ inputs.prerelease_suffix }}"

if [ -z "$SUFFIX" ]; then
SUFFIX="${BRANCH}.${GITHUB_RUN_NUMBER}"
fi

RELEASE_VERSION="${VERSION}-${SUFFIX}"
RELEASE_TAG="$RELEASE_VERSION"
PRERELEASE="true"
fi
echo "value=$VERSION" >> "$GITHUB_OUTPUT"

IMAGE_TAG="${RELEASE_VERSION#v}"

echo "value=$RELEASE_VERSION" >> "$GITHUB_OUTPUT"
echo "base_value=$VERSION" >> "$GITHUB_OUTPUT"
echo "image_tag=$IMAGE_TAG" >> "$GITHUB_OUTPUT"
echo "prerelease=$PRERELEASE" >> "$GITHUB_OUTPUT"
echo "tag_name=$RELEASE_TAG" >> "$GITHUB_OUTPUT"

- name: Set up QEMU (for multi-arch builds)
uses: docker/setup-qemu-action@v3
Expand All @@ -62,12 +97,10 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.image }}
tags: |
# Tag with full semver on version tags (e.g. v1.2.3 → 1.2.3)
type=semver,pattern={{version}}
# Tag with major.minor (e.g. 1.2)
type=semver,pattern={{major}}.{{minor}}
# Tag with resolved release version (stable tags and branch pre-releases)
type=raw,value=${{ steps.version.outputs.image_tag }}
# Only tag `latest` for stable releases (no pre-release suffix like -rc.1)
type=raw,value=latest,enable=${{ !contains(github.ref_name, '-') }}
type=raw,value=latest,enable=${{ steps.version.outputs.prerelease == 'false' }}
# Always tag with short SHA for traceability
type=sha,prefix=sha-,format=short

Expand All @@ -94,22 +127,35 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Read VERSION file
id: version
run: |
VERSION=$(cat VERSION | tr -d '[:space:]')
echo "value=$VERSION" >> "$GITHUB_OUTPUT"

- name: Extract changelog for this version
run: |
VERSION="${{ steps.version.outputs.value }}"
# Extract the section between ## [$VERSION] and the next ## [
NOTES=$(awk "/^## \[$VERSION\]/{found=1; next} found && /^## \[/{exit} found{print}" CHANGELOG.md)
echo "$NOTES" > release-notes.md
BASE_VERSION="${{ needs.build-and-push.outputs.base_version }}"
VERSION="${{ needs.build-and-push.outputs.version }}"

# Extract the section between ## [BASE_VERSION] and the next ## [
NOTES=$(awk "/^## \[$BASE_VERSION\]/{found=1; next} found && /^## \[/{exit} found{print}" CHANGELOG.md)

- name: Generate quickstart package
if [ -z "$NOTES" ]; then
NOTES="Pre-release build from ${GITHUB_REF_NAME} (${GITHUB_SHA})."
fi

if [ "${{ needs.build-and-push.outputs.prerelease }}" = "true" ]; then
{
echo "Pre-release build"
echo
echo "Version: $VERSION"
echo "Branch: ${GITHUB_REF_NAME}"
echo "Commit: ${GITHUB_SHA}"
echo
echo "$NOTES"
} > release-notes.md
else
echo "$NOTES" > release-notes.md
fi

- name: Generate local quickstart package
run: |
VERSION="${{ steps.version.outputs.value }}"
VERSION="${{ needs.build-and-push.outputs.version }}"
DIR="mate-quickstart-${VERSION}"
mkdir -p "$DIR"

Expand All @@ -121,11 +167,38 @@ jobs:
cp quickstart/README.txt "$DIR/README.txt"

zip -r "mate-quickstart-${VERSION}.zip" "$DIR"
rm -rf "$DIR"

- name: Generate Azure quickstart package
run: |
VERSION="${{ needs.build-and-push.outputs.version }}"
DIR="mate-quickstart-azure-${VERSION}"
mkdir -p "$DIR"

# Copy all Azure quickstart files
cp quickstart-azure/.env.template "$DIR/.env.template"
cp quickstart-azure/README.md "$DIR/README.md"
cp quickstart-azure/QUICKSTART.md "$DIR/QUICKSTART.md"
cp quickstart-azure/DEPLOYMENT.md "$DIR/DEPLOYMENT.md"
cp quickstart-azure/check-prerequisites.ps1 "$DIR/check-prerequisites.ps1"
cp quickstart-azure/setup-env.ps1 "$DIR/setup-env.ps1"
cp quickstart-azure/deploy-whatif.ps1 "$DIR/deploy-whatif.ps1"
cp quickstart-azure/deploy.ps1 "$DIR/deploy.ps1"
cp quickstart-azure/setup-keyvault-secrets.ps1 "$DIR/setup-keyvault-secrets.ps1"
cp quickstart-azure/cleanup-rg.ps1 "$DIR/cleanup-rg.ps1"

zip -r "mate-quickstart-azure-${VERSION}.zip" "$DIR"
rm -rf "$DIR"

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: "${{ steps.version.outputs.value }}"
tag_name: "${{ needs.build-and-push.outputs.tag_name }}"
target_commitish: "${{ github.sha }}"
name: "${{ needs.build-and-push.outputs.version }}"
prerelease: ${{ needs.build-and-push.outputs.prerelease == 'true' }}
body_path: release-notes.md
files: mate-quickstart-${{ steps.version.outputs.value }}.zip
files: |
mate-quickstart-${{ needs.build-and-push.outputs.version }}.zip
mate-quickstart-azure-${{ needs.build-and-push.outputs.version }}.zip
fail_on_unmatched_files: true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ Thumbs.db
#concept store
docs/concepts/

infra/azure/scripts/.pg-password
.gitignore
infra/azure/scripts/.credentials
101 changes: 100 additions & 1 deletion BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@
| E21 | CI/CD — GitHub Actions & Quickstart | Done |
| E22 | Module Tier Labels (Free / Premium) | Done |
| E23 | Run Report Enhancements (Tags, Refine Rubric, Draft Rubric Sets) | Done |
| E24 | Azure Deployment Automation & Release Packaging | Done |

---

## E24 — Azure Deployment Automation & Release Packaging *(v0.6.1)* ✅

- `[x]` PostgreSQL firewall automation — post-deployment rule creation for Azure service connectivity (E24-01)
- `[x]` Blob storage secret automation — automatic connection string injection and binding during deployment (E24-02)
- `[x]` Standalone Azure quickstart package — `quickstart-azure/` with README, QUICKSTART, DEPLOYMENT guides, .env template, and 6 PowerShell scripts (E24-03)
- `[x]` Manual prerelease workflows — GitHub Actions `workflow_dispatch` for branch-triggered prereleases with dynamic versioning (E24-04)
- `[x]` Dual package generation — automated release workflow creates both Docker Compose and Azure quickstart ZIPs; both attached to GitHub Release (E24-05)
- `[x]` Release metadata automation — conditional prerelease marking, versioned image tags, `latest` tag only for stable releases (E24-06)

---

Expand Down Expand Up @@ -134,6 +146,93 @@ GetCapabilities() : List<string> — declares what the module can do
- [x] **~~E1-04~~** *(obsolete — SQLite removed)* ~~Create `data/` directory gitkeep in mate root so local SQLite file path works~~
- [ ] **E1-12** Sample data seeder — auto-create a sample agent, test suite, and 5 test cases on first startup when the database is empty
- [ ] **E1-13** Azure Container Apps IaC — Bicep + `azd` template for one-command production deployment; includes WebUI + Worker containers, managed identity, Azure SQL, Service Bus
- [ ] **E1-13a** Full planning document (non-wiki): `docs/concepts/azure-container-landscape-plan.md` — target landscape, profile sizing, scale-to-zero strategy, implementation phases, cost model
- [ ] **E1-13b** Create `infra/azure/` IaC baseline — `main.bicep`, module split (container apps, postgres, storage, service bus, key vault, diagnostics), `azd` templates with installer-driven environment scope selection
- [ ] **E1-13c** Flexible sizing profiles (`XS`,`S`,`M`,`L`) — parameterized min/max replicas, CPU/memory, queue thresholds, and cooldown values; internal development default is `dev` + `S`
- [ ] **E1-13d** Implement Azure Service Bus `IMessageQueue` provider in `mate.Infrastructure.Azure` for durable cross-instance run execution
- [ ] **E1-13e** Refactor Worker execution path from DB polling to queue consumption (`test-runs`) so KEDA/ACA can scale worker replicas from zero based on queue depth
- [ ] **E1-13f** Add dedicated migration job in deployment flow; remove startup migration race between WebUI and Worker in cloud mode
- [ ] **E1-13g** Configure worker scale-to-zero (`minReplicas=0`) with queue-based scale rules; configure web profile (`prod min>=1`, non-prod optionally `min=0`)
- [ ] **E1-13h** Add non-prod cost mode automation — off-hours schedule to scale web/worker down, with morning warm-up schedule and override controls
- [ ] **E1-13i** Add DLQ and replay operations — dead-letter policy, replay command/runbook, and alerting for poison messages
- [ ] **E1-13j** Add production observability and cost governance — OpenTelemetry export, dashboards, budget alerts, and cost-anomaly alerts
- [ ] **E1-13k** Add production readiness runbooks — deployment/rollback, queue incident handling, backup/restore checks, key rotation, and scale policy tuning; seed with `docs/concepts/container-stack-update-runbook.md`
- [ ] **E1-13l** Add installer prompt contract — installation asks for environment scope and size profile, validates allowed combinations, and writes deterministic deployment parameters

#### E1-13 Implementation TODO Board (Execution Order)

- [ ] **T1** Backlog hygiene + scope lock (`E1-13a`)
- [ ] Resolve duplicate E1 IDs (`E1-08`, `E1-09`) to unique IDs
- [ ] Freeze internal engineering scope to `dev` only
- [ ] Freeze internal engineering size to `S`
- [ ] Confirm installer options: scope + profile (`XS`,`S`,`M`,`L`)

- [ ] **T2** IaC baseline (`E1-13b`)
- [ ] Create `infra/azure/` with Bicep modules (ACA, PostgreSQL, Blob, Service Bus, Key Vault, diagnostics)
- [ ] Add `azd` templates that can generate selected scope during installation
- [ ] Add CI validation for Bicep (lint/what-if)

- [ ] **T3** Flexible sizing and installer prompt (`E1-13c`, `E1-13l`)
- [ ] Add parameter files for `XS`/`S`/`M`/`L`
- [ ] Wire installation prompt for scope and profile selection
- [ ] Validate selected scope/profile combinations and emit deterministic parameter files
- [ ] Document internal default: `dev` + `S`

- [ ] **T4** Queue provider implementation (`E1-13d`)
- [ ] Implement Azure Service Bus `IMessageQueue`
- [ ] Keep WebUI enqueue path for `test-runs`
- [ ] Add integration tests for enqueue/consume/ack/abandon

- [ ] **T5** Worker refactor to queue consumption (`E1-13e`)
- [ ] Replace DB polling with queue consume path in Azure mode
- [ ] Implement idempotency and safe retry behavior
- [ ] Validate concurrent processing limits

- [ ] **T6** Migration job and startup race removal (`E1-13f`)
- [ ] Add dedicated migration step/job in deployment
- [ ] Remove migration race between WebUI and Worker
- [ ] Add deployment gate: app rollout only after migration success

- [ ] **T7** Scale-to-zero and autoscaling (`E1-13g`)
- [ ] Worker `minReplicas=0` with queue-based scale rule
- [ ] Web profile: `prod min>=1`, non-prod optional `min=0`
- [ ] Tune thresholds/cooldowns from test telemetry

- [ ] **T8** Non-prod cost mode automation (`E1-13h`)
- [ ] Add off-hours scale-down schedule
- [ ] Add morning warm-up schedule and override
- [ ] Capture baseline vs optimized cost report

- [ ] **T9** DLQ and replay operations (`E1-13i`)
- [ ] Configure dead-letter + retry limits
- [ ] Add replay workflow/runbook
- [ ] Add alerts for poison-message spikes

- [ ] **T10** Observability and governance (`E1-13j`)
- [ ] Enable OpenTelemetry + Azure Monitor dashboards
- [ ] Alert on queue lag, run failure rate, cold-start latency
- [ ] Configure budget + cost anomaly alerts

- [ ] **T11** Operations runbooks (`E1-13k`)
- [ ] Deployment and rollback playbook
- [ ] Queue incident and DLQ replay playbook
- [ ] Backup/restore + key-rotation playbook

- [ ] **T12** Health and readiness dependency (`E10-01`, `E10-02`)
- [ ] Implement `/health/live`
- [ ] Implement `/health/ready` with DB/blob/queue checks
- [ ] Wire probes into Azure Container Apps

- [ ] **T13** Security dependency (`E1-08`)
- [ ] Implement Key Vault `ISecretService`
- [ ] Enforce Managed Identity in Azure mode
- [ ] Validate secret rotation and access policies

- [ ] **T14** Release progression and go-live
- [ ] Validate internally on `dev` with `S` profile
- [ ] Validate installer-selected rollout scope and profile logic
- [ ] Hypercare window with daily performance/cost review
- [ ] Sign-off against E1-13 acceptance criteria

---

Expand Down Expand Up @@ -646,4 +745,4 @@ All connectors implement `IAgentConnectorModule` with `ModuleId`, `DisplayName`,

---

*Last updated: 2026-03-04, v0.6.0 released*
*Last updated: 2026-03-05, v0.6.0 released*
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- **Azure deployment automation** — Post-deployment automation in `deploy.ps1` for PostgreSQL firewall rule creation, blob storage secret injection, and connection string binding; idempotent for both WebUI and Worker containers (E13-13a).
- **Standalone Azure quickstart package** — `quickstart-azure/` directory with complete deployment guide, configuration template, and all 6 PowerShell scripts; enables one-command deployment without git clone (E13-13b).
- **`quickstart-azure/README.md`** — Comprehensive Azure deployment guide with prerequisites, 5-step workflow, profiles (xs/s/m/l), cost estimates, troubleshooting, and architecture details (E13-13b).
- **`quickstart-azure/QUICKSTART.md`** — Quick reference for rapid deployment (3-5 minutes); includes scripts overview, deployment options, and cleanup instructions (E13-13b).
- **`quickstart-azure/DEPLOYMENT.md`** — Technical reference documentation for post-deployment workflow phases and verification (E13-13b).
- **Manual prerelease workflows** — GitHub Actions `workflow_dispatch` trigger enabling prerelease creation from any branch; supports dynamic prerelease versioning (v0.6.0-branch.runNumber or custom suffix) (E21-21b).
- **Dual quickstart package generation** — GitHub Actions automatically generates both `mate-quickstart-<version>.zip` (Docker Compose) and `mate-quickstart-azure-<version>.zip` (Azure deployment) during release; both attached to GitHub Release (E21-21b).

### Changed
- **README.md quickstart order** — Reordered deployment options: Option B now Deploy to Azure (recommended), Option C now Build from Source (E13-13c).
- **GitHub Actions release workflow** — Extended `docker-publish.yml` with `workflow_dispatch` input for prerelease suffix; conditional prerelease marking in GitHub Release; separate image tagging logic for stable vs. prerelease versions (E21-21b).
- **Release package generation** — Post-deployment steps now handle postgres-conn, blob-conn, and all 10 quickstart-azure files; ZIP generation for both local and Azure packages (E21-21b).
- **Docker image tagging** — `latest` tag only applied to stable releases from version tags; prerelease versions use versioned tags only (E21-21b).

---

## [v0.6.0] — 2026-03-04
Expand Down
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,25 @@ Open **<http://localhost:5000>**. Images are pulled from GitHub Container Regist

> **Tip:** Pin a specific version by replacing `:latest` with the version tag in `docker-compose.yml`, e.g. `:0.3.2`.

### Option B — Build from source
### Option B — Deploy to Azure

Download the `mate-quickstart-azure-<version>.zip` from [GitHub Releases](https://github.com/holgerimbery/mate/releases/latest) or use the scripts in `infra/azure/scripts/`:

**Windows (PowerShell)**
```powershell
cd infra/azure/scripts
pwsh ./check-prerequisites.ps1 # Validate tools
pwsh ./setup-env.ps1 # Configure Azure credentials
pwsh ./deploy-whatif.ps1 # Preview changes (recommended)
pwsh ./deploy.ps1 # Deploy infrastructure
pwsh ./setup-keyvault-secrets.ps1 # Configure secrets & RBAC
```

See [quickstart-azure/README.md](quickstart-azure/README.md) for full deployment guide, troubleshooting, architecture details, and cost estimates.

> **Prerequisites:** Azure CLI, PowerShell 7+, Bicep CLI. Estimated deployment time: 3–5 minutes.

### Option C — Build from source

**Prerequisites:** [.NET 9 SDK](https://dotnet.microsoft.com/download) · [Docker Desktop](https://www.docker.com/products/docker-desktop/)

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.6.0
v0.6.1
4 changes: 4 additions & 0 deletions debug-container.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#!/usr/bin/env pwsh
# Copyright (c) Holger Imbery. All rights reserved.
# Licensed under the mate Custom License. See LICENSE in the project root.
# Commercial use of this file, in whole or in part, is prohibited without prior written permission.

<#
.SYNOPSIS
mate container management script.
Expand Down
2 changes: 1 addition & 1 deletion docs/wiki
Submodule wiki updated from 465a5f to ccc713
Loading