Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ce4a818
Add Adaptive Apps MicroHack foundation
djong1 Aug 19, 2026
1d8320c
Add Adaptive Apps dev container
djong1 Aug 19, 2026
a912060
Move dev container to repository configuration
djong1 Aug 19, 2026
a0059c1
Fix Windows dev container script execution
djong1 Aug 19, 2026
5ddf3f7
Secure K3s access with Azure Bastion
djong1 Aug 19, 2026
c807b37
Add portable application challenge
djong1 Aug 19, 2026
5da0aa5
Add adaptive identity challenge
djong1 Aug 19, 2026
2cbd777
Add adaptive AI challenge
djong1 Aug 19, 2026
3b2118e
Fix Adaptive Apps platform deployment for AKS and K3s (#1, #2)
Aug 21, 2026
8f42ee1
Merge pull request #9 from djong1/fix/adaptive-apps-platform-validation
djong1 Aug 21, 2026
f82d596
Handle Azure default outbound access retirement for the K3s VM
Aug 21, 2026
74a7cfa
Merge pull request #10 from djong1/fix/k3s-default-outbound-access
benvbr Aug 21, 2026
002d389
Make the NAT gateway the default outbound path for the K3s VM
Aug 21, 2026
a2b6661
Merge pull request #11 from djong1/fix/k3s-nat-gateway-default
benvbr Aug 21, 2026
51d0211
Explain resource type validation output
djong1 Aug 21, 2026
c804008
Clarify portable app challenge handoff
djong1 Aug 21, 2026
24ef176
Add managed identity fallback for Radius setup
djong1 Aug 21, 2026
91a28f8
Initialize trading PostgreSQL recipes
djong1 Aug 21, 2026
8d0130c
Merge pull request #12 from djong1/djong1-initialize-azure-postgresql
djong1 Aug 21, 2026
da36ee3
Remove upgrade instructions for existing workshop
djong1 Sep 1, 2026
866e75d
Fix AKS egress IP parsing in Challenge 04 recipe configuration
djong1 Sep 1, 2026
a92bd06
Fix InvalidTagNameCharacters on Azure resources in Radius recipes
djong1 Sep 1, 2026
5cf2281
Merge pull request #13 from djong1/djong1-fix-aks-egress-ip-parsing
djong1 Sep 1, 2026
8ce8002
Merge pull request #14 from djong1/djong1-fix-azure-tag-names
djong1 Sep 1, 2026
1f425b9
Serialize PostgreSQL flexible server child resources
djong1 Sep 1, 2026
2bd7aa1
Merge pull request #15 from djong1/djong1-serialize-postgres-children
djong1 Sep 1, 2026
b85d19c
Nest recipe secrets inside the values map
djong1 Sep 1, 2026
9f27818
Merge pull request #16 from djong1/djong1-fix-recipe-secrets-contract
djong1 Sep 1, 2026
c256728
Keep the PostgreSQL recipe result evaluable so Radius records its values
djong1 Sep 1, 2026
93f274d
Merge pull request #17 from djong1/djong1-fix-recipe-output-evaluation
djong1 Sep 1, 2026
fb62ee5
Fix recipe secret consumption so the backend container can deploy
djong1 Sep 1, 2026
821daec
Merge pull request #18 from djong1/djong1-fix-recipe-secret-consumption
djong1 Sep 1, 2026
3529466
Fix the schema initializer Job, which has never run on a Windows chec…
djong1 Sep 2, 2026
e11f2c5
Merge pull request #19 from djong1/djong1-fix-schema-initializer-line…
djong1 Sep 2, 2026
0a2d2d9
Stop asking the application to do MQTT auth it cannot do (#20)
djong1 Sep 2, 2026
786464c
Finish challenge-05: place orders, verify them in Azure, document the…
djong1 Sep 2, 2026
78b71c5
Add Challenge 09: model, review, and deploy with Radius Canvas (#22)
djong1 Sep 4, 2026
7587f50
Clarify the two audiences and Hack Console provisioning in the Adapti…
djong1 Sep 4, 2026
5dd35c0
Update Readme.md
djong1 Sep 4, 2026
7f9fa52
Update Readme to remove outdated references
djong1 Sep 4, 2026
c58a60f
Merge branch 'feature-adaptive-apps' into djong1-adaptive-apps-microhack
djong1 Sep 4, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"name": "Azure / App Innovation / Adaptive Apps",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/microhack,type=bind,consistency=cached",
"workspaceFolder": "/workspaces/microhack/03-Azure/01-01-App Innovation/04-adaptive-apps",
"remoteUser": "vscode",
"features": {
"ghcr.io/devcontainers/features/azure-cli:1": {
"version": "2.89.1"
},
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": false,
"installOhMyZsh": false,
"upgradePackages": false
},
"ghcr.io/devcontainers/features/powershell:2": {
"version": "stable"
}
},
"mounts": [
"source=adaptive-apps-microhack-azure-${devcontainerId},target=/home/vscode/.azure,type=volume",
"source=adaptive-apps-microhack-kube-${devcontainerId},target=/home/vscode/.kube,type=volume",
"source=adaptive-apps-microhack-radius-${devcontainerId},target=/home/vscode/.rad,type=volume",
"source=adaptive-apps-microhack-ssh-${devcontainerId},target=/home/vscode/.ssh,type=volume"
],
"postCreateCommand": "bash /workspaces/microhack/.devcontainer/03-azure-01-01-app-innovation-04-adaptive-apps/post-create.sh",
"postAttachCommand": "code Readme.md",
"remoteEnv": {
"PATH": "${containerEnv:PATH}:/home/vscode/.local/bin"
},
"forwardPorts": [
3000,
8080,
7007
],
"portsAttributes": {
"3000": {
"label": "Adaptive Apps frontend",
"onAutoForward": "notify"
},
"8080": {
"label": "Keycloak identity broker",
"onAutoForward": "notify"
},
"7007": {
"label": "Radius dashboard",
"onAutoForward": "notify"
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-azuretools.vscode-bicep",
"ms-kubernetes-tools.vscode-kubernetes-tools",
"ms-vscode.powershell",
"timonwong.shellcheck"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "bash"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#!/usr/bin/env bash
set -euo pipefail
trap 'echo "ERROR: Adaptive Apps devcontainer setup failed at line ${LINENO}." >&2' ERR

readonly KUBECTL_VERSION="v1.36.3"
readonly HELM_VERSION="v3.21.4"
readonly RADIUS_VERSION="v0.60.0"
readonly YQ_VERSION="v4.53.4"
readonly BICEP_VERSION="v0.46.1"
readonly BASTION_EXTENSION_VERSION="1.4.3"

retry() {
local attempts="$1"
shift
local count=1

until "$@"; do
if [[ "$count" -ge "$attempts" ]]; then
return 1
fi
count=$((count + 1))
sleep 2
done
}

case "$(uname -m)" in
x86_64)
readonly ARCH="amd64"
readonly BICEP_PLATFORM="linux-x64"
;;
aarch64 | arm64)
readonly ARCH="arm64"
readonly BICEP_PLATFORM="linux-arm64"
;;
*)
echo "Unsupported architecture: $(uname -m)" >&2
exit 1
;;
esac

for state_directory in "$HOME/.azure" "$HOME/.kube" "$HOME/.rad" "$HOME/.ssh"; do
sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" "$state_directory"
done

sudo apt-get update
sudo apt-get install --yes --no-install-recommends \
ca-certificates \
curl \
git \
jq \
openssh-client \
tar
sudo rm -rf /var/lib/apt/lists/*

mkdir -p "$HOME/.local/bin"
if ! grep -Fqx 'export PATH="$HOME/.local/bin:$PATH"' "$HOME/.bashrc"; then
echo 'export PATH="$HOME/.local/bin:$PATH"' >>"$HOME/.bashrc"
fi
export PATH="$HOME/.local/bin:$PATH"

configure_windows_worktree_shell() {
local git_pointer="/workspaces/microhack/.git"
local marker="# Adaptive Apps Windows worktree prompt"

if [[ ! -f "$git_pointer" ]] ||
! grep -Eq '^gitdir: [A-Za-z]:[/\\]' "$git_pointer"; then
return
fi

if ! grep -Fqx "$marker" "$HOME/.bashrc"; then
cat >>"$HOME/.bashrc" <<'EOF'

# Adaptive Apps Windows worktree prompt
# The bound .git file points to Windows-only worktree metadata. Avoid probing it.
unset PROMPT_COMMAND
PS1='\u@\h:\w\$ '
EOF
fi

echo "Windows Git worktree detected. Repository-aware Git commands are unavailable"
echo "inside this container; the MicroHack commands do not require them."
}

install_kubectl() {
local checksum
retry 3 curl --fail --location --silent --show-error \
"https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${ARCH}/kubectl" \
--output "$HOME/.local/bin/kubectl"
checksum="$(retry 3 curl --fail --location --silent --show-error \
"https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${ARCH}/kubectl.sha256")"
printf '%s %s\n' "$checksum" "$HOME/.local/bin/kubectl" | sha256sum --check
chmod 0755 "$HOME/.local/bin/kubectl"
}

install_helm() {
local checksum
local temporary_directory
temporary_directory="$(mktemp -d)"

retry 3 curl --fail --location --silent --show-error \
"https://get.helm.sh/helm-${HELM_VERSION}-linux-${ARCH}.tar.gz" \
--output "$temporary_directory/helm.tgz"
checksum="$(retry 3 curl --fail --location --silent --show-error \
"https://get.helm.sh/helm-${HELM_VERSION}-linux-${ARCH}.tar.gz.sha256sum" |
awk '{ print $1 }')"
printf '%s %s\n' "$checksum" "$temporary_directory/helm.tgz" |
sha256sum --check
(
cd "$temporary_directory"
tar -xzf helm.tgz
)
install -m 0755 \
"$temporary_directory/linux-${ARCH}/helm" \
"$HOME/.local/bin/helm"
rm -rf "$temporary_directory"
}

install_radius() {
retry 3 curl --fail --location --silent --show-error \
"https://raw.githubusercontent.com/radius-project/radius/${RADIUS_VERSION}/deploy/install.sh" \
--output /tmp/install-radius.sh
bash /tmp/install-radius.sh \
--version "$RADIUS_VERSION" \
--install-dir "$HOME/.local/bin"
rm -f /tmp/install-radius.sh
}

install_yq() {
local checksum
local checksums
local yq_asset="yq_linux_${ARCH}"

retry 3 curl --fail --location --silent --show-error \
"https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${yq_asset}" \
--output "$HOME/.local/bin/yq"
checksums="$(retry 3 curl --fail --location --silent --show-error \
"https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums")"
checksum="$(awk -v asset="$yq_asset" '$1 == asset { print $19 }' <<<"$checksums")"
[[ -n "$checksum" ]] || {
echo "No SHA-256 checksum found for ${yq_asset}." >&2
return 1
}
printf '%s %s\n' "$checksum" "$HOME/.local/bin/yq" | sha256sum --check
chmod 0755 "$HOME/.local/bin/yq"
}

verify_tooling() {
local command_name
local missing=0

echo
echo "Adaptive Apps MicroHack tool verification:"
for command_name in az kubectl helm rad git jq yq curl pwsh ssh tar; do
if ! command -v "$command_name" >/dev/null 2>&1; then
echo "ERROR: required command not found: ${command_name}" >&2
missing=1
else
printf '%-8s %s\n' "$command_name" "$(command -v "$command_name")"
fi
done

if ! az bicep version >/dev/null 2>&1; then
echo "ERROR: Azure CLI Bicep is not available." >&2
missing=1
else
printf '%-8s %s\n' "bicep" "az bicep"
fi
if ! az network bastion tunnel --help >/dev/null 2>&1; then
echo "ERROR: Azure CLI Bastion tunnel support is not available." >&2
missing=1
else
printf '%-8s %s\n' "bastion" "$(az extension show --name bastion --query version --output tsv)"
fi

if [[ "$missing" -ne 0 ]]; then
echo "Devcontainer setup is incomplete. Rebuild the container or rerun:" >&2
echo "bash /workspaces/microhack/.devcontainer/03-azure-01-01-app-innovation-04-adaptive-apps/post-create.sh" >&2
return 1
fi
}

configure_windows_worktree_shell
install_kubectl
install_helm
install_radius
install_yq
retry 3 az extension add \
--name bastion \
--version "$BASTION_EXTENSION_VERSION" \
--upgrade \
--yes \
--allow-preview false \
--output none
retry 3 az bicep install \
--version "$BICEP_VERSION" \
--target-platform "$BICEP_PLATFORM"
verify_tooling

echo
echo "Adaptive Apps MicroHack tool versions:"
az version --query '"azure-cli"' --output tsv | sed 's/^/azure-cli: /'
az bicep version
kubectl version --client
helm version --short
rad version
pwsh --version
git --version
jq --version
yq --version
az extension show --name bastion --query version --output tsv | sed 's/^/bastion extension: /'
ssh -V

echo
echo "The container is ready. Sign in with 'az login' and select the lab subscription."
47 changes: 21 additions & 26 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
# Shell scripts execute inside Linux containers and must retain LF line endings.
*.sh text eol=lf

# Enforce consistent line endings across Windows + Linux environments.
* text=auto eol=lf

# Keep Windows command scripts with CRLF for compatibility.
*.bat text eol=crlf
*.cmd text eol=crlf

# Treat common binary formats as binary.
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.webp binary
*.ico binary
*.pdf binary
*.zip binary
*.tgz binary
*.gz binary
*.jar binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary
"/.gitattributes" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/**/*.sh" text eol=lf
"/.devcontainer/03-azure-01-01-app-innovation-04-adaptive-apps/*.sh" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/Readme.md" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/challenges/challenge-05.md" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/challenges/challenge-06.md" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/challenges/challenge-08.md" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/walkthrough/challenge-05/solution-05.md" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/walkthrough/challenge-06/solution-06.md" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/walkthrough/challenge-08/solution-08.md" text eol=lf
# Anything that is executed or interpreted inside a container must keep LF endings. Bicep
# preserves on-disk line endings verbatim through loadTextContent() and multi-line strings,
# so a CRLF checkout embeds carriage returns into recipe shell scripts and breaks them at
# runtime. These are globs rather than a per-file allowlist: listing files individually is
# how iac/recipes/postgres-*.bicep came to be missed.
"/03-Azure/01-01-App Innovation/04-adaptive-apps/**/*.bicep" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/**/*.sql" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/**/*.yaml" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/**/*.yml" text eol=lf
"/03-Azure/01-01-App Innovation/04-adaptive-apps/iac/bicepconfig.json" text eol=lf
"/.devcontainer/03-azure-01-01-app-innovation-04-adaptive-apps/devcontainer.json" text eol=lf
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Exclude .vscode directory
.vscode

# Adaptive Apps Bicep resource-type extension generated during Challenge 03.
/03-Azure/01-01-App Innovation/04-adaptive-apps/artifacts/*.tgz

# Dev Containers feature lock file generated on the first container build.
.devcontainer/**/devcontainer-lock.json

Expand Down
Loading
Loading