Skip to content

Azure: improve logging#264

Draft
lionello wants to merge 4 commits into
mainfrom
lio/add-integ-test
Draft

Azure: improve logging#264
lionello wants to merge 4 commits into
mainfrom
lio/add-integ-test

Conversation

@lionello

@lionello lionello commented May 20, 2026

Copy link
Copy Markdown
Member
  • Use azure-monitor for logging to Basic tier tables
  • Add integration test

Summary by CodeRabbit

  • New Features

    • Added CD automation with Pulumi Automation API for Azure, AWS, and GCP (preview/up/down/refresh/destroy).
    • Multi-cloud preview and deployment operations plus local run script and compose/test project fixtures.
  • Tests

    • Added integration tests for Azure/AWS/GCP previews and new unit tests for env/config helpers and event collection.
  • Chores

    • Switched Azure logging to Azure Monitor.
    • Updated Azure SDK dependencies.
    • Expanded CLI allowlist to include Azure role assignment show.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 197f5749-2799-4462-a36a-6ffae7e28ee0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR restructures the CD command entrypoint from global environment variables into a cdMain control flow, removes explicit resource parenting from Azure provider resources, switches Container Apps logging from log-analytics to azure-monitor with diagnostic settings, refactors tests into integration-focused golden comparisons, and adds comprehensive testdata fixtures.

Changes

CD Command Entrypoint Refactoring

Layer / File(s) Summary
CD main control flow and config parsing
cd/cd_main.go
cdMain implements Pulumi Automation entrypoint with per-command execution (up, preview, down, destroy, refresh, cancel, outputs, list). Helper functions parse color settings, generate project/stack config with autonaming/provider disabling, select cloud provider from environment variables, and coordinate event collection/uploading.
Run entrypoint refactor
cd/main.go
run now accepts variadic args ...string instead of reading os.Args directly; routes version/usage handling and cdMain invocation.
Environment variable helpers
cd/envs.go, cd/envs_test.go
envs.go removes global var initialization block. envs_test.go adds unit tests for getenv(), splitByComma(), and getenvBool() helper functions with environment manipulation.
Upload function URL parameters
cd/upload.go, cd/upload_test.go
uploadEvents and uploadState now accept explicit portal upload URLs as parameters and early-return if URL is empty. Tests updated to pass URLs explicitly instead of mutating globals.
CD main unit tests
cd/cd_main_test.go
Tests for color() environment handling, projectConfig() with/without prefix, stackConfigFromEnv() cloud provider selection (AWS/GCP/Azure), and collectEvents() gzip event marshaling.
Integration test refactoring
cd/main_test.go
Replaces unit tests with integration-focused suite (//go:build integration). Adds TestRunVersion, TestRunUsageError, and provider-specific preview tests (Azure/AWS/GCP) that normalize nondeterminism (autonaming suffixes, debug diagnostics, timestamps) and compare against golden JSON snapshots.
CD dependencies and CLI permissions
cd/go.mod, .claude/settings.json
cd/go.mod adds testify, connectrpc/connect, and indirect dependencies. .claude/settings.json expands Azure CLI allowlist (account, containerapp, group, monitor diagnostic-settings, log-analytics, role assignment).
CD bash entrypoint
cd/run.sh
New bash wrapper exporting Azure environment variables, setting local upload URLs, enabling Pulumi diff, and invoking Go program with base64-encoded payload.

Azure Provider Resource Parenting Refactoring

Layer / File(s) Summary
ACR task context parameter removal
provider/defangazure/azure/acr.go, provider/defangazure/azure/image.go
createACRTask removes contextURL parameter and associated logging; buildServiceImage no longer passes svc.Build.Context.
DNS zone private link parenting
provider/defangazure/azure/dns.go
Postgres and Redis private DNS virtual network links are created with caller-provided opts only, removing explicit pulumi.Parent(<zone>) calls.
LLM and private endpoint parenting
provider/defangazure/azure/llm.go
Cognitive Services deployment and network private DNS zone group use opts only, removing pulumi.Parent for account and endpoint resources.
Postgres configuration parenting
provider/defangazure/azure/postgres.go
Removes intermediate serverChildOpts chaining. Child resources (extensions, no-TLS config, database, firewall rule) receive caller opts directly with explicit DependsOn ordering.
Redis database option merging
provider/defangazure/azure/redis.go
Redis database now uses common.MergeOptions(...) instead of direct append(opts, pulumi.Parent(...)) pattern.

Azure Container Apps Logging Architecture

Layer / File(s) Summary
Logging destination and diagnostic settings
provider/defangazure/project.go
Switches managed environment AppLogsConfiguration.Destination from log-analytics to azure-monitor. Adds explicit monitor.DiagnosticSetting for console/system log routing with LogAnalyticsDestinationType="Dedicated". Provisions dedicated console logs Log Analytics table with configured plan.
Console logs plan configuration
provider/defangazure/azure/recipe.go
New LogConsoleLogsPlan exported accessor (defang:log-console-logs-plan, default "Basic") with documentation for supported plan variants (Analytics, Auxiliary).

Test Fixtures and Configuration

Layer / File(s) Summary
Pulumi test configurations
cd/testdata/Pulumi.yaml, cd/testdata/Pulumi.azure.yaml
Pulumi.yaml defines crewai program with provider plugins (defang-aws/gcp/azure), autonaming patterns, and disabled default providers. Pulumi.azure.yaml specifies Azure Native settings (location, subscriptionId, tenantId) with metadata.
Docker Compose test configurations
cd/testdata/compose.cd.yaml, cd/testdata/compose.crewai.yaml
compose.cd.yaml defines AWS/Azure/GCP CD services with provider-specific environment and credential mounts. compose.crewai.yaml defines six-service application (app, chat, embedding, postgres, redis, worker) with networks, dependencies, and resource reservations.
Azure testdata and entrypoint
cd/testdata/.defang/azure, cd/testdata/main.go
.defang/azure contains Azure environment variables; main.go loads compose.crewai.yaml and invokes Pulumi with ProjectUpdate.
Azure preview events golden snapshot
cd/testdata/preview-events-azure.json
Comprehensive JSON fixture of sequential Pulumi preview events (diagnostic setting, managed environment, Log Analytics workspace/table, resource group, container app, providers, stack) with normalized timestamps/sequences for golden comparison.
Root module dependencies
go.mod
Updates pulumi-azure-native-sdk submodule versions from v3.16.0 to v3.17.0 (monitor, network, operationalinsights, etc.).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • DefangLabs/pulumi-defang#201: Both modify the event collection and upload pipeline—this PR changes collectEvents/uploadEvents signatures to accept explicit URLs while #201 adjusts marshaling and upload timing.
  • DefangLabs/pulumi-defang#165: Both expand .claude/settings.json permissions allowlist for Azure CLI commands and Pulumi operations.

Suggested labels

azure

Suggested reviewers

  • edwardrf
  • jordanstephens

"A rabbit cheered as code took flight,
Env vars moved and tests shone bright.
Azure logs now routed true,
Events uploaded, golden view.
Hops of joy — CI green in sight."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Azure: improve logging' accurately reflects the main changes in the PR, which focus on improving Azure's logging infrastructure by switching to azure-monitor and adding comprehensive integration tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lio/add-integ-test

Comment @coderabbitai help to get the list of available commands and usage tips.

@lionello lionello marked this pull request as draft May 20, 2026 22:44
@lionello lionello changed the title Add integration test Azure: improve logging May 20, 2026
@lionello lionello requested a review from edwardrf May 20, 2026 22:44
@lionello lionello temporarily deployed to defang-staging May 20, 2026 22:46 — with GitHub Actions Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (2)
.claude/settings.json (1)

7-21: ⚡ Quick win

Tighten the new Azure CLI allowlist.

These additions permit broad subscription-wide enumeration (account list, group list, workspace/table list, and role-assignment reads), which expands the assistant’s read scope beyond the specific integration resources under test. Prefer the narrowest show or resource-scoped commands you can support here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/settings.json around lines 7 - 21, The allowlist currently includes
broad Azure CLI "list" commands (e.g., "Bash(az account list:*)", "Bash(az group
list:*)", "Bash(az monitor log-analytics workspace table list:*)", "Bash(az role
assignment list:*)") which enable subscription-wide enumeration; replace those
with the narrowest resource-scoped or "show" variants (or remove them) so the
assistant only has read access to the specific integration resources under
test—update the listed entries (for example, keep "Bash(az account show:*)",
"Bash(az group show:*)", "Bash(az monitor log-analytics workspace show:*)",
"Bash(az monitor log-analytics workspace table show:*)", and remove or tighten
the corresponding "list" and "role assignment list" lines) to restrict scope.
cd/run.sh (1)

4-5: ⚡ Quick win

Use per-run temp files for upload artifacts.

Fixed /tmp/events-azure.json and /tmp/states-azure.json paths will collide across parallel or repeated runs, which makes the integration output easy to clobber or misread. Generate unique files per invocation instead.

Suggested change
-export DEFANG_EVENTS_UPLOAD_URL=file:///tmp/events-azure.json
-export STATES_EVENTS_UPLOAD_URL=file:///tmp/states-azure.json
+events_file="$(mktemp /tmp/events-azure.XXXXXX.json)"
+states_file="$(mktemp /tmp/states-azure.XXXXXX.json)"
+export DEFANG_EVENTS_UPLOAD_URL="file://${events_file}"
+export STATES_EVENTS_UPLOAD_URL="file://${states_file}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cd/run.sh` around lines 4 - 5, The environment variables
DEFANG_EVENTS_UPLOAD_URL and STATES_EVENTS_UPLOAD_URL currently point to fixed
files (/tmp/events-azure.json and /tmp/states-azure.json) which will collide
across parallel or repeated runs; change the script to generate unique per-run
temp file paths (e.g., via mktemp or by including $$ and a timestamp) and assign
those generated file paths to DEFANG_EVENTS_UPLOAD_URL and
STATES_EVENTS_UPLOAD_URL so each invocation writes to its own artifact file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cd/cd_main.go`:
- Around line 36-46: The code currently validates projectName and stackName
before parsing the command, causing `cd help` or empty-command help to fail with
usage/env errors; reorder logic in the function so you first parse args into
command (client.CdCommand using args and the `args` slice) and handle
help/empty-command cases before checking required environment variables
(projectName and stackName) and returning usageError; apply the same reorder to
the similar block referenced around the second occurrence (lines 51-57) so help
is always honored prior to env validation.
- Around line 97-100: The call to auto.SelectStackInlineSource in the
client.CdCommandList branch is swallowing its error (stack, _ =
auto.SelectStackInlineSource(...)) and later code accesses stack.Workspace(),
which can panic if selection failed; change the branch to capture and check the
error from auto.SelectStackInlineSource(ctx, stackName, projectName, nil),
return or propagate the error immediately when non-nil (with context including
stackName/projectName), and only proceed to use stack.Workspace() when err ==
nil so downstream code is safe.

In `@cd/run.sh`:
- Around line 2-11: Remove the hardcoded Azure tenant/subscription/client
variables and stop unconditionally overriding caller-provided values: instead,
read AZURE_SUBSCRIPTION_ID, AZURE_LOCATION, AZURE_TENANT_ID, and AZURE_CLIENT_ID
from the environment (use them only if set) and provide safe defaults only for
non-sensitive vars like STACK, PROJECT, DEFANG_*; ensure the script fails fast
or errors if the required AZURE_* credentials are missing so callers must supply
valid account IDs rather than using baked-in values.

In `@cd/testdata/compose.cd.yaml`:
- Line 16: Replace the incorrect environment variable name
STATES_EVENTS_UPLOAD_URL with DEFANG_STATES_UPLOAD_URL in the compose CD YAML
(every occurrence at lines shown in the review), so the runtime code that reads
DEFANG_STATES_UPLOAD_URL will find the URL; update all instances (e.g.,
STATES_EVENTS_UPLOAD_URL -> DEFANG_STATES_UPLOAD_URL) to match the application's
expected variable name and ensure consistency with the already-correct
DEFANG_EVENTS_UPLOAD_URL.

In `@cd/testdata/main.go`:
- Around line 12-15: The code ignores the error from os.ReadFile before building
the ProjectUpdate; change the read to capture the error (e.g., compose, err :=
os.ReadFile(...)) and if err != nil handle it immediately (log/processLogger or
fmt.Fprintln to stderr and exit non‑zero) before calling
pulumi.Run(program.NewRun(&defangv1.ProjectUpdate{Compose: compose})); ensure
you return/exit on error so pulumi.Run is never invoked with an invalid/empty
compose payload.

In `@cd/testdata/preview-events-azure.json`:
- Around line 27-29: The diagnostic JSON comparison is failing because
developer-specific absolute plugin paths (e.g., the "using
pulumi-resource-defang-azure from $PATH at /Users/…/go/bin/…") aren't normalized
before the JSONEq assertion; update the test that runs the "cd preview"
diagnostics to add a regex normalization step (matching paths like "from \$PATH
at .*go/bin/[^\\s\"]+" or similar) that replaces the absolute plugin path in the
diagnostic "message" field with a stable placeholder, consistent with the
existing timestamp/sequence/random-suffix normalizers currently applied before
JSONEq so the golden comparison no longer depends on machine-specific install
locations.

In `@provider/defangazure/project.go`:
- Around line 388-410: Summary: Validate and normalize the LogConsoleLogsPlan
value before passing it to ARM to fail fast on typos. After retrieving
providerazure.LogConsoleLogsPlan via providerazure.LogConsoleLogsPlan.Get(ctx)
(consoleLogsPlan), resolve/convert it to a canonical string, normalize case,
check it is one of "Basic", "Analytics", or "Auxiliary", and if not return an
error (or stop creation) with a clear message; then pass the normalized value
into operationalinsights.TableArgs.Plan in the NewTable call (or use a validated
pulumi.StringOutput) so ARM never sees invalid plans.

---

Nitpick comments:
In @.claude/settings.json:
- Around line 7-21: The allowlist currently includes broad Azure CLI "list"
commands (e.g., "Bash(az account list:*)", "Bash(az group list:*)", "Bash(az
monitor log-analytics workspace table list:*)", "Bash(az role assignment
list:*)") which enable subscription-wide enumeration; replace those with the
narrowest resource-scoped or "show" variants (or remove them) so the assistant
only has read access to the specific integration resources under test—update the
listed entries (for example, keep "Bash(az account show:*)", "Bash(az group
show:*)", "Bash(az monitor log-analytics workspace show:*)", "Bash(az monitor
log-analytics workspace table show:*)", and remove or tighten the corresponding
"list" and "role assignment list" lines) to restrict scope.

In `@cd/run.sh`:
- Around line 4-5: The environment variables DEFANG_EVENTS_UPLOAD_URL and
STATES_EVENTS_UPLOAD_URL currently point to fixed files (/tmp/events-azure.json
and /tmp/states-azure.json) which will collide across parallel or repeated runs;
change the script to generate unique per-run temp file paths (e.g., via mktemp
or by including $$ and a timestamp) and assign those generated file paths to
DEFANG_EVENTS_UPLOAD_URL and STATES_EVENTS_UPLOAD_URL so each invocation writes
to its own artifact file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4007b7ab-f397-4196-8853-e9966dc50103

📥 Commits

Reviewing files that changed from the base of the PR and between 759dd21 and fa67969.

⛔ Files ignored due to path filters (2)
  • cd/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (29)
  • .claude/settings.json
  • cd/cd_main.go
  • cd/cd_main_test.go
  • cd/envs.go
  • cd/envs_test.go
  • cd/go.mod
  • cd/main.go
  • cd/main_test.go
  • cd/run.sh
  • cd/testdata/.defang/azure
  • cd/testdata/Pulumi.azure.yaml
  • cd/testdata/Pulumi.yaml
  • cd/testdata/compose.cd.yaml
  • cd/testdata/compose.crewai.yaml
  • cd/testdata/main.go
  • cd/testdata/preview-events-aws.json
  • cd/testdata/preview-events-azure.json
  • cd/testdata/preview-events-gcp.json
  • cd/upload.go
  • cd/upload_test.go
  • go.mod
  • provider/defangazure/azure/acr.go
  • provider/defangazure/azure/dns.go
  • provider/defangazure/azure/image.go
  • provider/defangazure/azure/llm.go
  • provider/defangazure/azure/postgres.go
  • provider/defangazure/azure/recipe.go
  • provider/defangazure/azure/redis.go
  • provider/defangazure/project.go
💤 Files with no reviewable changes (3)
  • provider/defangazure/azure/acr.go
  • cd/envs.go
  • provider/defangazure/azure/image.go

Comment thread cd/cd_main.go
Comment on lines +36 to +46
if projectName == "" {
return &usageError{msg: "missing required environment variable: PROJECT"}
}
if stackName != strings.ToLower(stackName) {
return &usageError{msg: "STACK name must be lowercase"}
}

var command client.CdCommand
if len(args) > 1 {
command = client.CdCommand(args[1])
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle help/empty command before requiring PROJECT.

Right now Line 36 enforces PROJECT before command parsing, so cd help can fail with usage/env errors instead of showing help. Move command parsing/help handling ahead of required env validation.

Also applies to: 51-57

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cd/cd_main.go` around lines 36 - 46, The code currently validates projectName
and stackName before parsing the command, causing `cd help` or empty-command
help to fail with usage/env errors; reorder logic in the function so you first
parse args into command (client.CdCommand using args and the `args` slice) and
handle help/empty-command cases before checking required environment variables
(projectName and stackName) and returning usageError; apply the same reorder to
the similar block referenced around the second occurrence (lines 51-57) so help
is always honored prior to env validation.

Comment thread cd/cd_main.go
Comment on lines +97 to +100
case client.CdCommandList:
// List doesn't need a real stack, but select something so we can call ListStacks on the workspace.
stack, _ = auto.SelectStackInlineSource(ctx, stackName, projectName, nil)
default:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t ignore stack selection errors in list flow.

Line 99 discards the error from auto.SelectStackInlineSource, but Line 240 then uses stack.Workspace(). If selection fails, this can break list unexpectedly. Handle and return the error explicitly.

Suggested fix
 case client.CdCommandList:
 	// List doesn't need a real stack, but select something so we can call ListStacks on the workspace.
-	stack, _ = auto.SelectStackInlineSource(ctx, stackName, projectName, nil)
+	stack, err = auto.SelectStackInlineSource(ctx, stackName, projectName, nil)
+	if err != nil {
+		return pulumiErr(err)
+	}

Also applies to: 240-246

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cd/cd_main.go` around lines 97 - 100, The call to
auto.SelectStackInlineSource in the client.CdCommandList branch is swallowing
its error (stack, _ = auto.SelectStackInlineSource(...)) and later code accesses
stack.Workspace(), which can panic if selection failed; change the branch to
capture and check the error from auto.SelectStackInlineSource(ctx, stackName,
projectName, nil), return or propagate the error immediately when non-nil (with
context including stackName/projectName), and only proceed to use
stack.Workspace() when err == nil so downstream code is safe.

Comment thread cd/run.sh
Comment on lines +2 to +11
export STACK=lioazure
export PROJECT=test
export DEFANG_EVENTS_UPLOAD_URL=file:///tmp/events-azure.json
export STATES_EVENTS_UPLOAD_URL=file:///tmp/states-azure.json
export DEFANG_PULUMI_DIFF=1

export AZURE_SUBSCRIPTION_ID=f311c4db-e998-4c94-906c-7e2637303a05
export AZURE_LOCATION=westus
export AZURE_TENANT_ID=12c0f515-fa47-402f-9982-de7646d3cb28
export AZURE_CLIENT_ID=80fc261c-daa9-4d91-86f7-74c110dac086

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t bake a single Azure account into the shared runner.

This script commits environment-specific Azure identifiers and unconditionally overrides any caller-provided values, so it will fail for anyone outside that tenant/subscription and is awkward to reuse in CI. Require the account IDs from the environment and keep only safe defaults in the script.

Suggested change
 #!/usr/bin/env bash
-export STACK=lioazure
-export PROJECT=test
-export DEFANG_EVENTS_UPLOAD_URL=file:///tmp/events-azure.json
-export STATES_EVENTS_UPLOAD_URL=file:///tmp/states-azure.json
-export DEFANG_PULUMI_DIFF=1
+set -euo pipefail
+
+export STACK="${STACK:-lioazure}"
+export PROJECT="${PROJECT:-test}"
+export DEFANG_EVENTS_UPLOAD_URL="${DEFANG_EVENTS_UPLOAD_URL:-file:///tmp/events-azure.json}"
+export STATES_EVENTS_UPLOAD_URL="${STATES_EVENTS_UPLOAD_URL:-file:///tmp/states-azure.json}"
+export DEFANG_PULUMI_DIFF="${DEFANG_PULUMI_DIFF:-1}"
 
-export AZURE_SUBSCRIPTION_ID=f311c4db-e998-4c94-906c-7e2637303a05
-export AZURE_LOCATION=westus
-export AZURE_TENANT_ID=12c0f515-fa47-402f-9982-de7646d3cb28
-export AZURE_CLIENT_ID=80fc261c-daa9-4d91-86f7-74c110dac086
+export AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:?set AZURE_SUBSCRIPTION_ID}"
+export AZURE_LOCATION="${AZURE_LOCATION:-westus}"
+export AZURE_TENANT_ID="${AZURE_TENANT_ID:?set AZURE_TENANT_ID}"
+export AZURE_CLIENT_ID="${AZURE_CLIENT_ID:?set AZURE_CLIENT_ID}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export STACK=lioazure
export PROJECT=test
export DEFANG_EVENTS_UPLOAD_URL=file:///tmp/events-azure.json
export STATES_EVENTS_UPLOAD_URL=file:///tmp/states-azure.json
export DEFANG_PULUMI_DIFF=1
export AZURE_SUBSCRIPTION_ID=f311c4db-e998-4c94-906c-7e2637303a05
export AZURE_LOCATION=westus
export AZURE_TENANT_ID=12c0f515-fa47-402f-9982-de7646d3cb28
export AZURE_CLIENT_ID=80fc261c-daa9-4d91-86f7-74c110dac086
set -euo pipefail
export STACK="${STACK:-lioazure}"
export PROJECT="${PROJECT:-test}"
export DEFANG_EVENTS_UPLOAD_URL="${DEFANG_EVENTS_UPLOAD_URL:-file:///tmp/events-azure.json}"
export STATES_EVENTS_UPLOAD_URL="${STATES_EVENTS_UPLOAD_URL:-file:///tmp/states-azure.json}"
export DEFANG_PULUMI_DIFF="${DEFANG_PULUMI_DIFF:-1}"
export AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:?set AZURE_SUBSCRIPTION_ID}"
export AZURE_LOCATION="${AZURE_LOCATION:-westus}"
export AZURE_TENANT_ID="${AZURE_TENANT_ID:?set AZURE_TENANT_ID}"
export AZURE_CLIENT_ID="${AZURE_CLIENT_ID:?set AZURE_CLIENT_ID}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cd/run.sh` around lines 2 - 11, Remove the hardcoded Azure
tenant/subscription/client variables and stop unconditionally overriding
caller-provided values: instead, read AZURE_SUBSCRIPTION_ID, AZURE_LOCATION,
AZURE_TENANT_ID, and AZURE_CLIENT_ID from the environment (use them only if set)
and provide safe defaults only for non-sensitive vars like STACK, PROJECT,
DEFANG_*; ensure the script fails fast or errors if the required AZURE_*
credentials are missing so callers must supply valid account IDs rather than
using baked-in values.

Comment thread cd/testdata/compose.cd.yaml Outdated
- STACK=aws
- PROJECT=cd-test
- DEFANG_EVENTS_UPLOAD_URL=file:///tmp/defang-cd/events-aws.json
- STATES_EVENTS_UPLOAD_URL=file:///tmp/defang-cd/states-aws.json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find env var names and state upload wiring used by CD code.
rg -n -C3 'STATES_EVENTS_UPLOAD_URL|STATE_EVENTS_UPLOAD_URL|DEFANG_EVENTS_UPLOAD_URL|uploadState|uploadEvents'

Repository: DefangLabs/pulumi-defang

Length of output: 7247


🏁 Script executed:

rg -n 'statesUploadUrl' cd/cd_main.go

Repository: DefangLabs/pulumi-defang

Length of output: 326


Fix env var name: STATES_EVENTS_UPLOAD_URL should be DEFANG_STATES_UPLOAD_URL.

Lines 16, 37, and 60 use STATES_EVENTS_UPLOAD_URL, but the CD code reads DEFANG_STATES_UPLOAD_URL (see cd/cd_main.go:34). This mismatch causes state uploads to silently no-op because the URL environment variable is not found. The events upload correctly uses DEFANG_EVENTS_UPLOAD_URL.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cd/testdata/compose.cd.yaml` at line 16, Replace the incorrect environment
variable name STATES_EVENTS_UPLOAD_URL with DEFANG_STATES_UPLOAD_URL in the
compose CD YAML (every occurrence at lines shown in the review), so the runtime
code that reads DEFANG_STATES_UPLOAD_URL will find the URL; update all instances
(e.g., STATES_EVENTS_UPLOAD_URL -> DEFANG_STATES_UPLOAD_URL) to match the
application's expected variable name and ensure consistency with the
already-correct DEFANG_EVENTS_UPLOAD_URL.

Comment thread cd/testdata/main.go Outdated
Comment on lines +12 to +15
compose, _ := os.ReadFile("./compose.crewai.yaml")
pulumi.Run(program.NewRun(&defangv1.ProjectUpdate{
Compose: compose,
}))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and examine its content
cat -n cd/testdata/main.go

Repository: DefangLabs/pulumi-defang

Length of output: 527


🏁 Script executed:

# Check if make lint or golangci-lint is available
ls -la | grep -i makefile
cat Makefile | grep -A 5 "lint"

Repository: DefangLabs/pulumi-defang

Length of output: 950


🏁 Script executed:

# Check for golangci-lint configuration
fd -t f '.golangci' -o '.golangci.yaml' -o '.golangci.yml'

Repository: DefangLabs/pulumi-defang

Length of output: 216


🏁 Script executed:

# Look for golangci-lint config files with proper syntax
find . -maxdepth 2 -name ".golangci*" -type f

Repository: DefangLabs/pulumi-defang

Length of output: 85


🏁 Script executed:

# Check if there are any lint-related configurations or if linting should cover examples/cd
grep -r "examples" Makefile | head -20

Repository: DefangLabs/pulumi-defang

Length of output: 863


🏁 Script executed:

# Check if there's any documentation about where lint should be run
cat -n README.md | head -50

Repository: DefangLabs/pulumi-defang

Length of output: 4383


🏁 Script executed:

# Verify the actual scope of the lint target and whether examples/cd should be linted
rg "examples/cd|testdata" --type go

Repository: DefangLabs/pulumi-defang

Length of output: 299


🏁 Script executed:

# Check the exact linting scope and confirm cd/ is not included
cat -n .golangci.yaml | head -30

Repository: DefangLabs/pulumi-defang

Length of output: 787


🏁 Script executed:

# Verify if there are any other lint configurations or pre-commit hooks that might cover cd/
cat -n .pre-commit-config.yaml 2>/dev/null || echo "No pre-commit config"

Repository: DefangLabs/pulumi-defang

Length of output: 89


🏁 Script executed:

# Check if the cd/testdata directory has special status
ls -la cd/testdata/ | head -20

Repository: DefangLabs/pulumi-defang

Length of output: 800


🏁 Script executed:

# Check the full golangci.yaml to see if cd/ is excluded
cat .golangci.yaml

Repository: DefangLabs/pulumi-defang

Length of output: 2701


🏁 Script executed:

# Check the Makefile lint target scope again more carefully
cat Makefile | grep -A 10 "^lint:"

Repository: DefangLabs/pulumi-defang

Length of output: 597


🏁 Script executed:

# Verify what the actual error handling issue is - check if blank import is intentional
# by looking at similar patterns in the codebase
rg "_, err :=" --type go | head -10

Repository: DefangLabs/pulumi-defang

Length of output: 808


🏁 Script executed:

# Check if there's a specific pattern where errors are ignored in this codebase
rg "ReadFile\|os\.Open" --type go -A 2 | head -30

Repository: DefangLabs/pulumi-defang

Length of output: 50


🏁 Script executed:

# Check if cd/testdata/main.go is actual test code or just data
cat -n cd/testdata/main.go

Repository: DefangLabs/pulumi-defang

Length of output: 527


🏁 Script executed:

# Look for test files in cd/ to understand the testing structure
find cd -name "*_test.go" -type f

Repository: DefangLabs/pulumi-defang

Length of output: 172


🏁 Script executed:

# Check if the cd directory has its own purpose/documentation
cat cd/README.md 2>/dev/null || echo "No README in cd/"

Repository: DefangLabs/pulumi-defang

Length of output: 85


🏁 Script executed:

# Verify whether errcheck lint would catch this even if linting was run
# by checking the configuration settings for errcheck
rg "errcheck:" .golangci.yaml -A 10

Repository: DefangLabs/pulumi-defang

Length of output: 50


Handle file read errors before constructing ProjectUpdate.

Line 12 ignores the os.ReadFile error, allowing a nil or empty compose payload to propagate into the Pulumi run. This can cause misleading runtime failures instead of failing fast at the source.

Suggested fix
 func main() {
-	compose, _ := os.ReadFile("./compose.crewai.yaml")
+	compose, err := os.ReadFile("./compose.crewai.yaml")
+	if err != nil {
+		panic(err)
+	}
 	pulumi.Run(program.NewRun(&defangv1.ProjectUpdate{
 		Compose: compose,
 	}))
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
compose, _ := os.ReadFile("./compose.crewai.yaml")
pulumi.Run(program.NewRun(&defangv1.ProjectUpdate{
Compose: compose,
}))
compose, err := os.ReadFile("./compose.crewai.yaml")
if err != nil {
panic(err)
}
pulumi.Run(program.NewRun(&defangv1.ProjectUpdate{
Compose: compose,
}))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cd/testdata/main.go` around lines 12 - 15, The code ignores the error from
os.ReadFile before building the ProjectUpdate; change the read to capture the
error (e.g., compose, err := os.ReadFile(...)) and if err != nil handle it
immediately (log/processLogger or fmt.Fprintln to stderr and exit non‑zero)
before calling pulumi.Run(program.NewRun(&defangv1.ProjectUpdate{Compose:
compose})); ensure you return/exit on error so pulumi.Run is never invoked with
an invalid/empty compose payload.

Comment on lines +27 to +29
"prefix": "warning: ",
"message": "using pulumi-resource-defang-azure from $PATH at /Users/llunesu/go/bin/pulumi-resource-defang-azure\n",
"color": "never",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether test normalization handles absolute plugin path warnings.
rg -n -C3 'pulumi-resource-defang-azure|/Users/|warning:' cd/main_test.go cd/testdata/preview-events-azure.json

Repository: DefangLabs/pulumi-defang

Length of output: 688


🏁 Script executed:

# Check if the test file exists and get its size
wc -l cd/main_test.go

# Search for comparison/assertion logic and normalization
rg -n 'expect|golden|normalize|fixture|assert|CompareString|diff' cd/main_test.go | head -30

# Look for the specific event or fixture being used
rg -n 'preview-events|diagnosticEvent' cd/main_test.go

Repository: DefangLabs/pulumi-defang

Length of output: 556


🏁 Script executed:

# Read the test file with line numbers around the comparison
cat -n cd/main_test.go | sed -n '95,145p'

Repository: DefangLabs/pulumi-defang

Length of output: 2308


🏁 Script executed:

# Search for the diagnostic message source
rg -n 'using pulumi-resource' . --type go

# Also check if there's any mocking or environment setup
rg -n 'pulumi-resource-defang|mock|Mock' cd/main_test.go | head -20

Repository: DefangLabs/pulumi-defang

Length of output: 50


🏁 Script executed:

# Read the test function from the beginning
cat -n cd/main_test.go | sed -n '80,102p'

Repository: DefangLabs/pulumi-defang

Length of output: 1225


🏁 Script executed:

# Read further back to find the Preview call and uploaded variable
cat -n cd/main_test.go | sed -n '50,85p'

Repository: DefangLabs/pulumi-defang

Length of output: 1672


Normalize the absolute plugin path in diagnostic messages before golden comparison.

The test at line 72 executes a real cd preview command, which generates diagnostic output containing an absolute developer-specific path (/Users/llunesu/go/bin/pulumi-resource-defang-azure). While timestamps, sequences, and random suffixes are already normalized (lines 82–110), the diagnostic message string is not. This will cause JSONEq comparison to fail on any machine with a different plugin installation path. Add a regex normalization step (similar to the existing ones) to sanitize the plugin path from diagnostic messages before comparison.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cd/testdata/preview-events-azure.json` around lines 27 - 29, The diagnostic
JSON comparison is failing because developer-specific absolute plugin paths
(e.g., the "using pulumi-resource-defang-azure from $PATH at /Users/…/go/bin/…")
aren't normalized before the JSONEq assertion; update the test that runs the "cd
preview" diagnostics to add a regex normalization step (matching paths like
"from \$PATH at .*go/bin/[^\\s\"]+" or similar) that replaces the absolute
plugin path in the diagnostic "message" field with a stable placeholder,
consistent with the existing timestamp/sequence/random-suffix normalizers
currently applied before JSONEq so the golden comparison no longer depends on
machine-specific install locations.

Comment on lines +388 to +410
// Pin the plan on the console logs table (Container Apps' stdout sink).
// The table schema isn't a true workspace built-in — it's registered by
// the Container Apps Monitor solution, which attaches when an env links
// the workspace as its log-analytics destination. So we must wait for
// `env` before the table is queryable (or its ID resolvable for Import).
// Plain Create would race with the solution registration and fail with
// "cannot create already existing resource"; Import + DependsOn(env)
// guarantees the schema exists, then applies the Plan diff.
consoleLogsPlan := providerazure.LogConsoleLogsPlan.Get(ctx)
consoleLogsImportID := logWorkspace.ID().ToStringOutput().ApplyT(func(id string) pulumi.ID {
return pulumi.ID(id + "/tables/" + consoleLogsTable)
}).(pulumi.IDOutput)
if _, err := operationalinsights.NewTable(ctx, name+"-console-logs", &operationalinsights.TableArgs{
ResourceGroupName: infra.ResourceGroup.Name,
WorkspaceName: logWorkspace.Name,
TableName: pulumi.String(consoleLogsTable),
Plan: pulumi.String(consoleLogsPlan),
},
parentOpt,
pulumi.Parent(logWorkspace),
pulumi.DependsOn([]pulumi.Resource{diagSetting}),
pulumi.Import(consoleLogsImportID),
); err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate LogConsoleLogsPlan before sending it to ARM.

providerazure.LogConsoleLogsPlan.Get(ctx) is passed straight into operationalinsights.Table.Plan, so a typo like basic or Basci becomes a late Azure deployment error instead of a clear config error. Normalize and reject anything outside Basic, Analytics, and Auxiliary before creating the table.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@provider/defangazure/project.go` around lines 388 - 410, Summary: Validate
and normalize the LogConsoleLogsPlan value before passing it to ARM to fail fast
on typos. After retrieving providerazure.LogConsoleLogsPlan via
providerazure.LogConsoleLogsPlan.Get(ctx) (consoleLogsPlan), resolve/convert it
to a canonical string, normalize case, check it is one of "Basic", "Analytics",
or "Auxiliary", and if not return an error (or stop creation) with a clear
message; then pass the normalized value into operationalinsights.TableArgs.Plan
in the NewTable call (or use a validated pulumi.StringOutput) so ARM never sees
invalid plans.

@lionello lionello linked an issue May 21, 2026 that may be closed by this pull request
2 tasks
@lionello lionello temporarily deployed to defang-staging May 22, 2026 21:35 — with GitHub Actions Inactive
@lionello lionello marked this pull request as ready for review May 25, 2026 18:59
@lionello lionello marked this pull request as draft May 25, 2026 18:59
@lionello lionello force-pushed the lio/add-integ-test branch from b0595a8 to 04833a8 Compare May 25, 2026 23:50
@lionello lionello temporarily deployed to defang-staging May 25, 2026 23:53 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Azure: logs table tier, mastra $700/mo logs

1 participant