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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ devclaw status # Container state, FQDN, RG
devclaw logs # Tail logs until you see `[gateway] starting HTTP server`
```

If `devclaw` asks you to authenticate Azure CLI, run `devclaw login` for this repo profile and retry. This is typically needed for runtime operations (`logs`, `start`, `stop`, `restart`) and occasionally for live-state lookup.

`devclaw test` only prints a hint that points you at the in-container console. It does not exercise the model end-to-end. The fastest real smoke test is the WebChat UI below.

### Open the WebChat UI
Expand Down
60 changes: 55 additions & 5 deletions devclaw
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,22 @@ check_prereqs() {

get_app() {
RG=$(azd env get-value AZURE_RESOURCE_GROUP 2>/dev/null || true)
SUB=$(azd env get-value AZURE_SUBSCRIPTION_ID 2>/dev/null || true)
if [ -z "$RG" ]; then
echo -e " ${R}No deployment found. Run 'devclaw up' first.${N}"
exit 1
fi
Comment on lines 46 to 51
if ! az account show >/dev/null 2>&1; then
echo -e " ${Y}Azure CLI is not logged in for this workspace profile.${N}"
echo -e " ${D}Run 'devclaw login' and retry.${N}"
echo -e " ${D}Profile: ${AZURE_CONFIG_DIR}${N}"
exit 1
fi
if [ -n "$SUB" ] && ! az account set --subscription "$SUB" >/dev/null 2>&1; then
echo -e " ${Y}Azure CLI cannot access subscription ${SUB}.${N}"
echo -e " ${D}Run 'devclaw login' with an account that can access this subscription.${N}"
exit 1
fi
APP=$(az containerapp list --resource-group "$RG" --query "[0].name" -o tsv 2>/dev/null || true)
if [ -z "$APP" ]; then
echo -e " ${R}No container app found in $RG.${N}"
Expand Down Expand Up @@ -203,15 +215,53 @@ test)
;;

status)
get_app
RG=$(azd env get-value AZURE_RESOURCE_GROUP 2>/dev/null || true)
SUB=$(azd env get-value AZURE_SUBSCRIPTION_ID 2>/dev/null || true)
if [ -z "$RG" ]; then
echo -e " ${R}No deployment found. Run 'devclaw up' first.${N}"
exit 1
fi
Comment on lines +218 to +223

APP=""
SHOW_JSON=$(azd show -o json 2>/dev/null || true)
if [ -n "$SHOW_JSON" ]; then
RESOURCE_ID=$(printf '%s\n' "$SHOW_JSON" | grep -Eo '/subscriptions/[^\"]+/resourceGroups/[^\"]+/providers/Microsoft\.App/containerApps/[^\"]+' | head -1 || true)
if [ -n "$RESOURCE_ID" ]; then
APP="${RESOURCE_ID##*/}"
fi
fi

# Fallback if azd show did not include resource IDs yet.
if [ -z "$APP" ]; then
HOST=$(azd env get-value HOST_FQDN 2>/dev/null || true)
if [ -n "$HOST" ]; then
APP="${HOST%%.*}"
fi
fi
Comment on lines +234 to +240

if [ -z "$APP" ]; then
echo -e " ${R}No container app found in $RG.${N}"
echo -e " ${D}Try 'devclaw deploy' or check 'azd show'.${N}"
exit 1
fi

echo ""
echo -e " ${C}devclaw${N}"
echo -e " ${C}--------${N}"

FQDN=$(az containerapp show --name "$APP" --resource-group "$RG" \
--query "properties.configuration.ingress.fqdn" -o tsv 2>/dev/null)
STATUS=$(az containerapp revision list --name "$APP" --resource-group "$RG" \
--query "[?properties.active].properties.runningState" -o tsv 2>/dev/null | head -1)
FQDN=$(azd env get-value HOST_FQDN 2>/dev/null || true)
if [ -z "$FQDN" ] && [ -n "$SHOW_JSON" ]; then
FQDN=$(printf '%s\n' "$SHOW_JSON" | sed -n 's#.*"ingressUrl"[[:space:]]*:[[:space:]]*"https\{0,1\}://\([^/\"]*\)/\{0,1\}".*#\1#p' | head -1)
fi
Comment on lines +252 to +255

STATUS="unknown"
if az account show >/dev/null 2>&1; then
if [ -z "$SUB" ] || az account set --subscription "$SUB" >/dev/null 2>&1; then
STATUS=$(az containerapp revision list --name "$APP" --resource-group "$RG" \
--query "[?properties.active].properties.runningState" -o tsv 2>/dev/null | head -1)
[ -z "$STATUS" ] && STATUS="unknown"
fi
fi

SC="$Y"
[ "$STATUS" = "Running" ] && SC="$G"
Expand Down
Empty file modified infra/hooks/postdeploy.sh
100644 → 100755
Empty file.
Empty file modified infra/hooks/postprovision.sh
100644 → 100755
Empty file.
Empty file modified infra/hooks/predeploy.sh
100644 → 100755
Empty file.
34 changes: 27 additions & 7 deletions infra/hooks/preprovision.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,28 @@ fi

# Read a free-form azd env value (returns empty string if unset).
azd_flag() {
azd env get-value "$1" 2>/dev/null | tr -d '[:space:]' || true
local value

if ! value="$(azd env get-value "$1" 2>/dev/null)"; then
echo ""
return 0
fi

value="$(printf '%s' "$value" | tr -d '[:space:]')"

# `azd env get-value` may print error text when a key is missing.
case "$value" in
ERROR:*|Suggestion:*)
echo ""
;;
*)
echo "$value"
;;
esac
}

GUID_REGEX='[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'

# Some corporate tenants require a serviceManagementReference (an SMR GUID
# referencing a service catalogue / asset management record) on every new
# Entra ID app registration. When set, pass it through to `az ad app create`.
Expand All @@ -39,7 +58,7 @@ if [ -z "$SMR" ]; then
# Auto-detect: look for an SMR on the user's existing app registrations
echo "[preprovision] SERVICE_MANAGEMENT_REFERENCE not set — checking existing app registrations..."
DETECTED_SMR=$(az ad app list --show-mine --query "[?serviceManagementReference != null].serviceManagementReference | [0]" -o tsv 2>/dev/null || echo "")
if [[ "$DETECTED_SMR" =~ ^[0-9a-fA-F-]{36}$ ]]; then
if echo "$DETECTED_SMR" | grep -Eq "^$GUID_REGEX$"; then
echo "[preprovision] Auto-detected SMR from your existing apps: $DETECTED_SMR"
echo "[preprovision] Using it. To override, run: azd env set SERVICE_MANAGEMENT_REFERENCE <your-guid>"
SMR="$DETECTED_SMR"
Expand All @@ -65,11 +84,12 @@ fi
# Then re-run `devclaw up`. Existing deployments that already have a
# BOT_APP_ID continue to work without setting the flag.
# ---------------------------------------------------------------------------
EXISTING_APP_ID=$(azd env get-value BOT_APP_ID 2>/dev/null | grep -oP '^[0-9a-f-]+$' || echo "")
EXISTING_APP_ID=$(azd_flag BOT_APP_ID | grep -Eo "$GUID_REGEX" || echo "")
ENABLE_TEAMS_FLAG="$(azd_flag ENABLE_TEAMS)"
ENABLE_TEAMS_FLAG_LOWER="$(printf '%s' "$ENABLE_TEAMS_FLAG" | tr '[:upper:]' '[:lower:]')"
if [ -n "$EXISTING_APP_ID" ]; then
echo "[preprovision] Bot app registration already exists: $EXISTING_APP_ID"
elif [ "${ENABLE_TEAMS_FLAG,,}" != "true" ]; then
elif [ "$ENABLE_TEAMS_FLAG_LOWER" != "true" ]; then
echo "[preprovision] Teams integration not enabled — skipping bot app registration."
echo "[preprovision] To enable Teams later: azd env set ENABLE_TEAMS true && devclaw up"
else
Expand All @@ -81,7 +101,7 @@ else
--sign-in-audience "AzureADMyOrg" \
${SMR_ARGS[@]+"${SMR_ARGS[@]}"} \
--query appId -o tsv 2>&1)
APP_ID=$(echo "$APP_ERR" | grep -oP '^[0-9a-f-]{36}$' | head -1)
APP_ID=$(echo "$APP_ERR" | grep -Eo "$GUID_REGEX" | head -1)

if [ -z "$APP_ID" ]; then
echo "[preprovision] ERROR: Failed to create bot app registration"
Expand Down Expand Up @@ -129,7 +149,7 @@ fi
# Easy Auth — Entra ID app registration for ACA built-in authentication
# Forces Microsoft login before any request reaches the container
# ---------------------------------------------------------------------------
EXISTING_AUTH_ID=$(azd env get-value EASYAUTH_APP_ID 2>/dev/null | grep -oP '^[0-9a-f-]+$' || echo "")
EXISTING_AUTH_ID=$(azd_flag EASYAUTH_APP_ID | grep -Eo "$GUID_REGEX" || echo "")
if [ -n "$EXISTING_AUTH_ID" ]; then
echo "[preprovision] Easy Auth app registration already exists: $EXISTING_AUTH_ID"
else
Expand All @@ -144,7 +164,7 @@ else
--enable-id-token-issuance true \
${SMR_ARGS[@]+"${SMR_ARGS[@]}"} \
--query appId -o tsv 2>&1)
AUTH_APP_ID=$(echo "$AUTH_OUTPUT" | grep -oP '^[0-9a-f-]{36}$' | head -1)
AUTH_APP_ID=$(echo "$AUTH_OUTPUT" | grep -Eo "$GUID_REGEX" | head -1)

if [ -z "$AUTH_APP_ID" ]; then
echo "[preprovision] ERROR: Failed to create Easy Auth app registration"
Expand Down
1 change: 0 additions & 1 deletion infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ param environmentName string
'swedencentral'
'switzerlandnorth'
'uksouth'
'westcentralus'
])
@metadata({
azd: {
Expand Down