Repository navigation
Test two samples end to end on the LocalStack Azure emulator - #41
Conversation
Add a workflow that creates the AKS cluster on LocalStack for Azure, deploys the in-cluster PostgreSQL and Blob Storage samples, and checks each web app stores, lists and deletes an activity. Start the emulator with lstk in the README, since lstk does not ship the localstack CLI. Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
The script asks for the network configuration and node pool sizes. With no input the menu left the network settings empty and az aks create failed. Also fix the menu heading, which was copied from a Docker script. Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
There was a problem hiding this comment.
🟡 Changes recommended
The pull-request workflow exposes the LocalStack credential to same-repository PR-controlled code.
1 open finding
What changed in this PR
Adds LocalStack-based end-to-end validation for two Python AKS samples.
Changes:
- Adds a matrix workflow deploying and testing both samples.
- Adds deployment health and CRUD validation.
- Updates LocalStack instructions and network prompts.
| File | Description |
|---|---|
.github/workflows/samples.yml |
Adds LocalStack sample CI. |
tests/test-vacation-planner.sh |
Adds end-to-end application checks. |
scripts/01-system-assigned-managed-identity.sh |
Clarifies network prompt. |
scripts/01-user-assigned-managed-identity.sh |
Clarifies network prompt. |
README.md |
Documents LocalStack startup and testing. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Nice work! Deploying the samples on the emulator in CI closes a real gap, and both jobs are green. The one blocker is coverage: like the Samples CI in localstack-azure-samples, this workflow should test every sample in both languages, with the same options (a pull request runs the samples it touches, and a manual run can run all of them), and the HIGH comment carries a workflow and a test script for that.
1. Rules applied
Read from localstack/localstack-pro at origin/main (d223998f5a). Every file is paths:-scoped to localstack-pro-azure/**, so here they apply as principles, cited as "principle applied". I kept to this repo's own script conventions (#!/bin/bash, echo for progress, no strict mode in the sample scripts) and raised nothing against them.
localstack-pro-azure/CLAUDE.md.claude/rules/azure/common/:coding-style.md,hooks.md,patterns.md,security.md,testing.md.claude/rules/azure/python/:cloud-pipeline.md,coding-style.md,hooks.md,patterns.md,security.md,testing.md(no Python in the diff, so none applies).claude/rules/azure/scripts/:coding-style.md,hooks.md,patterns.md,security.md,testing.md.claude/rules/azure/emulator/azure-kubernetes-service.md, as background on the emulated AKS only
House precedent: the Samples CI in localstack/localstack-azure-samples (.github/workflows/run-samples.yml, run-samples.sh). This repo has no CLAUDE.md or AGENTS.md; its own gates are zizmor and gitleaks (pre-commit) plus actionlint. No rule file was missing or unreadable.
2. Existing comments
Copilot (one review, one HIGH comment on lines 13-15) asks to move this job off pull_request because same-repository branches can run code with LOCALSTACK_AUTH_TOKEN. I disagree with that remedy: only people with write access can push a branch here, and per GitHub, "any user with write access to your repository has read access to all secrets configured in your repository" (Secure use reference), so push or workflow_dispatch only would drop the PR check without narrowing who can reach the token. Fork PRs get no secrets at all, and the sibling Samples CI runs on pull_request the same way. If the token needs tighter scoping, the lever is an environment secret with protection rules (zizmor's auditor persona reports secrets-outside-env here), not the trigger. Copilot is right that fork PRs cannot pass, though: lstk start fails with authentication required: set LOCALSTACK_AUTH_TOKEN or run in interactive mode. The workflow attached to the HIGH comment skips them with a job-level if:.
3. Findings
All four are inline:
- HIGH,
.github/workflows/samples.ymlL29-L34: the workflow deploys 2 of the 20 sample apps (a Python app of two samples, no .NET at all). The comment attaches a workflow with one job per sample and language, for the samples a change touches or for all 20 on a manual run, and a test that drives both apps; the test runs green against real apps of both kinds locally. - MEDIUM,
tests/test-vacation-planner.shL51-L60: the "it is gone" check also passes on a page that lists nothing. - MEDIUM,
tests/test-vacation-planner.shL19-L21: a port-forward that cannot bind is silenced, and the checks then run against whatever owns the port. - LOW,
.github/workflows/samples.ymlL45: lstk is installed unpinned.
Both MEDIUMs were reproduced on a throwaway kind cluster with real kubectl and fixed by the suggested code; the fixes are also in the attached test script.
Out of scope (pre-existing, not in the diff)
samples/web-app-in-cluster-postgresql/{python,dotnet}/scripts/00-variables.sh set PREFIX='zeus', while the cluster scripts and the other nine samples use local. In this workflow the sample therefore creates its own zeus-rg and zeusacrtest and deploys from a registry the cluster was never attached to (--attach-acr localacrtest): the job log shows the push to zeusacrtest.azurecr.azure.localhost.localstack.cloud:4566 and a clean rollout. That works only because the emulated registry accepts unauthenticated access: az acr login logs Registry '...' did not issue a challenge., which azure-cli prints when GET /v2/ does not answer 401 with WWW-Authenticate. On Azure, --attach-acr grants AcrPull to the kubelet identity on the attached registry only (AKS and ACR integration), and anonymous pull is off by default (anonymous pull access), so the same steps would leave the pods in ImagePullBackOff. PREFIX='local' in both files would make this job exercise the attached registry. The emulator side (a registry data plane with no auth challenge, while the ARM resource reports anonymousPullEnabled: false) is a parity gap worth an issue in localstack-pro.
4. Clean files
scripts/01-system-assigned-managed-identity.shscripts/01-user-assigned-managed-identity.sh
The heading now names what the menu selects. Also checked in the workflow, no change needed: printf '1\n\n\n' matches the prompts (select reads 1, and both node-count prompts take their defaults on an empty line); lstk start --type azure records the type in config and returns once the emulator is ready; and lstk logs follows only with --follow (lstk v1.4.0, cmd/logs.go), so lstk logs | tail -300 cannot hang the failure step.
5. Verdict
Request changes. The workflow covers 2 of the 20 sample apps and should cover all of them, with the same run options as the sibling Samples CI. The rest is in good shape: the two MEDIUMs make the test fail closed instead of open, and the LOW pins lstk.
|
Thanks for the PR @HarshCasper, see GitHub Copilot and Claude Code PR reviews above. Please, make sure that all the Python and .NET samples are test in the GitHub Actions workflow, just like we do in run-samples.yml workflow in the LocalStack for Azure Samples repo. Or better, the run-samples.yml workflow only runs the samples touched by a PR, but you can also manually run it on demand and choose to run all the samples. This workflow should provide the same options. |
|
@HarshCasper I created and merged #44 to fix #35 issue raised by a user, an ex Microsoft colleague who kindly accepted to test our emulator. My PR modifies the |
Apply the review on #41: - The workflow builds its matrix from every samples/<sample>/<language> app. A pull request or push runs the apps it changes, and every app when the cluster script, the test or the workflow changes. A manual run picks run_mode changed (default) or all. Fork PRs are skipped, lstk is pinned to 1.4.0, and superseded runs are cancelled. - The test keeps cookies and sends the Razor Pages antiforgery token, so it drives the .NET apps too, and posts the Azure Files delete to /delete with activity_id. - The delete check keeps a second activity listed, so a page that lists nothing no longer passes. - The test stops when kubectl port-forward cannot bind instead of testing whatever owns the port. - The in-cluster PostgreSQL sample uses PREFIX local like the other samples, so it pulls from the registry attached to the cluster. Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
…ulator # Conflicts: # scripts/01-system-assigned-managed-identity.sh
…cate The SQL Database jobs failed with EulaNotAccepted on az sql server create. Set LOCALSTACK_MSSQL_ACCEPT_EULA=Y when starting the emulator, as the sample's README and the localstack-azure-samples CI do. mssql-tools18 encrypts by default and validates the server certificate, so pass -N -C to every sqlcmd call, as the localstack-azure-samples version of this sample does. Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
A cosmosdb-nosql-api job failed to create its AKS cluster: the emulator looks up the k3d release on api.github.com, and its anonymous calls hit the runner IP's 60 requests an hour with twenty jobs starting at once. Pass the run's read-only token as LOCALSTACK_GITHUB_API_TOKEN, as the localstack-azure-samples CI does. Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
|
Thanks @HarshCasper for the contribution and fixes. Please read my comments above and feel free to merge the PR when you are done with changes. |

The repo only linted its workflows. Nothing checked that the samples deploy and work on LocalStack for Azure.
Test samples on LocalStack for Azure, one job per sample app, Python and .NET (all 20):Select samplesjob builds the matrix from everysamples/<sample>/<language>app, as the localstack-azure-samples Samples CI does, so a new sample needs no workflow change.mainruns the apps whose folders it changes. It runs all 20 when it changes the cluster script, the test or the workflow.run_mode:changed(the default) orall.lstk start --type azure(lstk pinned to 1.4.0) and routesazto it withlstk az start-interceptionscripts/01-system-assigned-managed-identity.sh, piping in the answers to its prompts01,02,04and05scriptsLOCALSTACK_MSSQL_ACCEPT_EULA=Yfor the SQL Database sample.LOCALSTACK_GITHUB_API_TOKENset to the run's read-only token, so the emulator's k3d release lookups don't hit the anonymous GitHub API limit when 20 jobs start at once.tests/test-vacation-planner.sh <namespace> <service>:GET /healthreports the data service as reachable./deletewithactivity_id.kubectl port-forwardcan't bind, instead of testing whatever owns the port.sqlcmdcall passes-N -C. mssql-tools18 encrypts by default and validates the emulator's certificate.PREFIX='local'like the other samples, so it pulls from the registry attached to the cluster (it usedzeusand its own registry).scripts/01-user-assigned-managed-identity.sh: the network menu heading said "Run Docker Container (1-3)". It now matches the system-assigned script's "Select Network Plugin and Policy (1-3)".localstackCLI. They now uselstk start --type azure.Verified in CI: all 20 apps create the cluster, deploy and pass every check (run). actionlint, shellcheck, zizmor and gitleaks report nothing.