Skip to content

Use official Tilebox release runners across all clouds#7

Closed
snamber wants to merge 2 commits into
mainfrom
stefan/use-tilebox-release-runners
Closed

Use official Tilebox release runners across all clouds#7
snamber wants to merge 2 commits into
mainfrom
stefan/use-tilebox-release-runners

Conversation

@snamber

@snamber snamber commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add Azure infrastructure components alongside the existing AWS and GCP support
  • run the official ghcr.io/tilebox/runner:latest image across every provider
  • remove local image builders and private registry integration
  • add provider-native health checks, replacement, and rolling upgrade behavior
  • document runner requirements and the shared environment-variable contract

Verification

  • uv run ruff check .
  • uv run ruff format --check .
  • uv run pyright
  • uv lock --check
  • git diff --check
  • rendered AWS and GCP cloud-init YAML parses successfully
  • embedded AWS and GCP shell scripts pass bash -n

Summary by CodeRabbit

  • New Features
    • Added Azure infrastructure components for networks, managed identities, secrets, and autoscaling runner clusters.
    • Added a shared official runner image configuration across supported cloud platforms.
    • Added automated runner health monitoring and recovery signaling for AWS and GCP deployments.
  • Enhancements
    • Simplified cluster configuration by standardizing runner image handling and environment variables.
  • Documentation
    • Reworked the README with runner setup, configuration, deployment prerequisites, and multi-cloud component guidance.
    • Added development and architecture guidance for contributors.

snamber and others added 2 commits May 25, 2026 19:13
- Run the published Tilebox runner image across AWS, Azure, and GCP
- Add provider-native runner health checks and instance replacement
- Remove local image builders and private registry integration

Amp-Thread-ID: https://ampcode.com/threads/T-019f60ba-e218-745b-8fa8-ae9c31e00fbf
Co-authored-by: Amp <amp@ampcode.com>
@snamber
snamber requested a review from lukasbindreiter July 15, 2026 11:59
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The repository now documents and exports multi-cloud Tilebox runner infrastructure. AWS and GCP clusters use a shared runner image with cloud-specific health handling, while Azure gains network, identity, secret, VM scale-set, autoscaling, and cloud-init components.

Changes

Runner contract and package surface

Layer / File(s) Summary
Shared runner contract and exports
AGENTS.md, README.md, pyproject.toml, tilebox_iac/...
Documentation, dependencies, package exports, and the RUNNER_IMAGE constant define the AWS, Azure, and GCP component surface.

AWS runner health integration

Layer / File(s) Summary
AWS runner health integration
tilebox_iac/aws/auto_scaling_cluster.py, tilebox_iac/aws/cloud-init.yaml
AWS cloud-init uses the shared image, refreshes secrets, schedules container health checks, and grants permission to mark unhealthy instances in the Auto Scaling Group.

Azure runner infrastructure

Layer / File(s) Summary
Azure network, identity, and secrets
tilebox_iac/azure/__init__.py, tilebox_iac/azure/network.py, tilebox_iac/azure/identity.py, tilebox_iac/azure/secrets.py
Azure exports components for virtual networking, optional NAT, managed identities with RBAC assignments, and Key Vault secrets.
Azure VM scale-set runner
tilebox_iac/azure/auto_scaling_cluster.py, tilebox_iac/azure/cloud-init.yaml
AutoScalingCluster provisions a VM scale set, injects rendered cloud-init, configures optional Spot capacity and CPU autoscaling, and starts the runner and health services.

GCP runner health integration

Layer / File(s) Summary
GCP runner health integration
tilebox_iac/gcp/__init__.py, tilebox_iac/gcp/auto_scaling_cluster.py, tilebox_iac/gcp/cloud-init.yaml
GCP cluster initialization uses the shared image and configures a regional health check, ingress firewall, port-8080 endpoint, and MIG auto-healing.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Pulumi
  participant AzureAutoScalingCluster
  participant AzureManagedIdentity
  participant AzureVMScaleSet
  participant CloudInitServices
  Pulumi->>AzureAutoScalingCluster: create cluster component
  AzureAutoScalingCluster->>AzureManagedIdentity: create identity and dependencies
  AzureAutoScalingCluster->>AzureVMScaleSet: provision VM scale set with custom_data
  AzureVMScaleSet->>CloudInitServices: execute cloud-init
  CloudInitServices->>CloudInitServices: fetch secrets and start runner
  CloudInitServices->>CloudInitServices: expose health endpoint
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: switching AWS, Azure, and GCP to the official Tilebox runner image.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch stefan/use-tilebox-release-runners

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
tilebox_iac/gcp/auto_scaling_cluster.py (1)

106-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid mutating the input roles dictionary in place.

If the caller passes a shared roles dictionary, mutating it here by appending secret_roles and updating roles will cause those modifications to leak and compound if the dictionary is reused for other clusters. Consider creating a shallow copy of the dictionary before modifying it.

♻️ Proposed refactor
         if roles is None:
             roles = {"roles": list(required_roles)}
         else:
+            roles = roles.copy()
             configured_roles = set(roles.get("roles", []))
             roles["roles"] = list(required_roles | configured_roles)
🤖 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 `@tilebox_iac/gcp/auto_scaling_cluster.py` around lines 106 - 124, The
role-building logic mutates the caller’s roles dictionary in place, causing
changes to leak across reused configurations. In the surrounding function,
create a shallow copy of the provided roles dictionary before updating "roles"
and extending "secret_roles", while preserving the existing defaults and merged
role behavior.
🤖 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 `@tilebox_iac/azure/auto_scaling_cluster.py`:
- Around line 54-63: Validate that environment_variables contains the required
TILEBOX_API_KEY before provisioning, and reject the cluster configuration when
it is absent. Keep TILEBOX_CLUSTER optional and preserve the existing
secret-versus-regular environment variable handling in the loop.
- Around line 13-14: Update the Jinja Environment initialization in
auto_scaling_cluster.py to disable HTML autoescaping for the cloud-init
template, while preserving the existing FileSystemLoader and cloud-init.yaml
loading behavior.
- Around line 102-108: Update the VMSS configuration’s compute.UpgradePolicyArgs
in the cluster definition to include automatic_repairs_policy using
compute.AutomaticRepairsPolicyArgs with enabled=True, grace_period="PT10M", and
repair_action="Replace".

In `@tilebox_iac/azure/cloud-init.yaml`:
- Around line 19-31: Update get_access_token and fetch_secret in cloud-init.yaml
to fail when IMDS or Key Vault requests return errors or when the expected
token/value fields are missing or null. Use curl’s failure mode and jq
validation, then ensure invalid results are rejected before secrets are appended
to /tmp/secrets.env or the runner starts.

---

Nitpick comments:
In `@tilebox_iac/gcp/auto_scaling_cluster.py`:
- Around line 106-124: The role-building logic mutates the caller’s roles
dictionary in place, causing changes to leak across reused configurations. In
the surrounding function, create a shallow copy of the provided roles dictionary
before updating "roles" and extending "secret_roles", while preserving the
existing defaults and merged role behavior.
🪄 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: 48d4fa47-fe4f-4334-b1c3-cd671a91833c

📥 Commits

Reviewing files that changed from the base of the PR and between 61b9397 and 4f8414d.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • AGENTS.md
  • README.md
  • pyproject.toml
  • tilebox_iac/__init__.py
  • tilebox_iac/aws/__init__.py
  • tilebox_iac/aws/auto_scaling_cluster.py
  • tilebox_iac/aws/cloud-init.yaml
  • tilebox_iac/aws/image_builder.py
  • tilebox_iac/azure/__init__.py
  • tilebox_iac/azure/auto_scaling_cluster.py
  • tilebox_iac/azure/cloud-init.yaml
  • tilebox_iac/azure/identity.py
  • tilebox_iac/azure/network.py
  • tilebox_iac/azure/secrets.py
  • tilebox_iac/gcp/__init__.py
  • tilebox_iac/gcp/auto_scaling_cluster.py
  • tilebox_iac/gcp/cloud-init.yaml
  • tilebox_iac/gcp/image_builder.py
  • tilebox_iac/release_runner.py
💤 Files with no reviewable changes (4)
  • tilebox_iac/aws/init.py
  • tilebox_iac/gcp/image_builder.py
  • tilebox_iac/gcp/init.py
  • tilebox_iac/aws/image_builder.py

Comment on lines +13 to +14
env = Environment(loader=FileSystemLoader(Path(__file__).parent), autoescape=True)
template = env.get_template("cloud-init.yaml")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Repository files:\n'
git ls-files 'tilebox_iac/azure/auto_scaling_cluster.py' 'tilebox_iac/azure/cloud-init.yaml' || true

printf '\nAST outline for auto_scaling_cluster.py:\n'
ast-grep outline tilebox_iac/azure/auto_scaling_cluster.py --view expanded || true

printf '\nLine count for cloud-init.yaml:\n'
wc -l tilebox_iac/azure/cloud-init.yaml || true

printf '\nRelevant snippets:\n'
sed -n '1,220p' tilebox_iac/azure/auto_scaling_cluster.py
printf '\n--- cloud-init.yaml ---\n'
sed -n '1,220p' tilebox_iac/azure/cloud-init.yaml

Repository: tilebox/tilebox-iac

Length of output: 14955


Remove HTML autoescaping from the cloud-init template. autoescape=True will encode YAML and systemd values like &, <, and quotes into HTML entities, breaking the rendered cloud-init output. Use a non-HTML Jinja environment 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 `@tilebox_iac/azure/auto_scaling_cluster.py` around lines 13 - 14, Update the
Jinja Environment initialization in auto_scaling_cluster.py to disable HTML
autoescaping for the cloud-init template, while preserving the existing
FileSystemLoader and cloud-init.yaml loading behavior.

Comment on lines +54 to +63
used_secrets: dict[str, Secret] = {}
envs: dict[str, Input[str]] = {}
if environment_variables is not None:
for key in sorted(environment_variables):
value = environment_variables[key]
if isinstance(value, Secret):
used_secrets[key] = value
else:
envs[key] = value

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject clusters without TILEBOX_API_KEY.

The current optional dictionary permits deployment without the required runner credential, producing instances that cannot service work. Validate key presence before provisioning; continue allowing TILEBOX_CLUSTER to be absent.

Proposed validation
         used_secrets: dict[str, Secret] = {}
         envs: dict[str, Input[str]] = {}
+        if environment_variables is None or "TILEBOX_API_KEY" not in environment_variables:
+            raise ValueError("environment_variables must include TILEBOX_API_KEY")
+
         if environment_variables is not None:

As per coding guidelines, TILEBOX_API_KEY must be required while TILEBOX_CLUSTER remains optional.

📝 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
used_secrets: dict[str, Secret] = {}
envs: dict[str, Input[str]] = {}
if environment_variables is not None:
for key in sorted(environment_variables):
value = environment_variables[key]
if isinstance(value, Secret):
used_secrets[key] = value
else:
envs[key] = value
used_secrets: dict[str, Secret] = {}
envs: dict[str, Input[str]] = {}
if environment_variables is None or "TILEBOX_API_KEY" not in environment_variables:
raise ValueError("environment_variables must include TILEBOX_API_KEY")
if environment_variables is not None:
for key in sorted(environment_variables):
value = environment_variables[key]
if isinstance(value, Secret):
used_secrets[key] = value
else:
envs[key] = value
🤖 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 `@tilebox_iac/azure/auto_scaling_cluster.py` around lines 54 - 63, Validate
that environment_variables contains the required TILEBOX_API_KEY before
provisioning, and reject the cluster configuration when it is absent. Keep
TILEBOX_CLUSTER optional and preserve the existing secret-versus-regular
environment variable handling in the loop.

Source: Coding guidelines

Comment on lines +102 to +108
upgrade_policy=compute.UpgradePolicyArgs(
mode=compute.UpgradeMode.ROLLING,
rolling_upgrade_policy=compute.RollingUpgradePolicyArgs(
# New VMs rerun cloud-init; quota fallback does not.
max_surge=True,
),
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## outline\n'
ast-grep outline tilebox_iac/azure/auto_scaling_cluster.py --view expanded || true

printf '\n## relevant lines\n'
nl -ba tilebox_iac/azure/auto_scaling_cluster.py | sed -n '1,220p'

printf '\n## search repair policy usage\n'
rg -n "automatic_repairs_policy|automatic repairs|repair.*policy|repair_policy" tilebox_iac -S || true

Repository: tilebox/tilebox-iac

Length of output: 550


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## auto_scaling_cluster.py"
sed -n '1,240p' tilebox_iac/azure/auto_scaling_cluster.py

echo
echo "## repair-policy search"
rg -n "automatic_repairs_policy|automaticRepairsPolicy|repair.*policy|health_extension|ApplicationHealth" tilebox_iac -S || true

Repository: tilebox/tilebox-iac

Length of output: 11578


🌐 Web query:

Azure VMSS Application Health extension automatic repairs policy replacement pulumi azure native 3.x AutomaticRepairsPolicyArgs

💡 Result:

In Azure Virtual Machine Scale Sets (VMSS), the Application Health extension and the Automatic Repairs policy are not replacements for one another; rather, they are complementary components that must work together to enable automatic instance repairs [1][2]. The Application Health extension serves as the monitoring mechanism that determines whether an instance is healthy or unhealthy [1][2]. The Automatic Repairs policy, configured via automaticRepairsPolicy (or AutomaticRepairsPolicyArgs in Pulumi's azure-native 3.x provider), acts as the orchestrator that performs a specified repair action (such as replace, restart, or reimage) when an instance is flagged as unhealthy [1][3]. To implement automatic repairs in your Pulumi azure-native infrastructure code, you must configure both: 1. Application Health Extension: You must attach this extension to your VMSS so that it can monitor and report the health status of instances [1][2]. 2. Automatic Repairs Policy: You define this policy in your VirtualMachineScaleSet resource using the automaticRepairsPolicy property [4][1]. In Pulumi azure-native 3.x, the AutomaticRepairsPolicyArgs object accepts the following parameters [4][3]: - enabled (boolean): Specifies whether automatic repairs are enabled (default is false) [5][3]. - gracePeriod (string): The duration (ISO 8601 format, e.g., "PT10M") to suspend repairs after a state change, allowing the instance time to settle [5][3]. - repairAction (string): The action to take when an instance is unhealthy (e.g., "replace", "restart", "reimage") [5][1][3]. If you find that an instance is reported as unhealthy but not being repaired, ensure that the automaticRepairsPolicy is enabled and that the service state is set to Running [6]. You cannot replace the policy itself with the extension; they are distinct requirements for the automatic repair feature to function [1][7][8].

Citations:


🌐 Web query:

Pulumi azure-native Python AutomaticRepairsPolicyArgs enabled grace_period repair_action Replace

💡 Result:

In the Pulumi azure-native Python provider, AutomaticRepairsPolicyArgs is used to configure automatic instance repairs for a Virtual Machine Scale Set (VMSS) [1][2]. To use it, you pass an instance of this class to the automatic_repairs_policy argument within the VirtualMachineScaleSet resource properties [1][2]. The AutomaticRepairsPolicyArgs class typically includes the following properties: enabled (bool): Specifies whether automatic repairs should be enabled on the VMSS. The default is false [1]. grace_period (str): The duration for which automatic repairs are suspended after a VM state change to prevent premature repairs. It must be specified in ISO 8601 format (e.g., PT10M for 10 minutes) [1]. The allowed range is between 10 minutes (PT10M, which is the default) and 90 minutes (PT90M) [1]. repair_action (str): The action to perform on unhealthy VMs. Valid values are 'Replace', 'Restart', or 'Reimage'. The default value is 'Replace' [1][3][4]. Example usage pattern: import pulumi_azure_native.compute as compute vmss_repairs = compute.VirtualMachineScaleSet( "vmss", properties=compute.VirtualMachineScaleSetPropertiesArgs( automatic_repairs_policy=compute.AutomaticRepairsPolicyArgs( enabled=True, grace_period="PT15M", repair_action="Replace"), #... other required properties), #... other required parameters)

Citations:


Enable automatic repairs on the VMSS. The Application Health extension only reports health; add automatic_repairs_policy=compute.AutomaticRepairsPolicyArgs(enabled=True, grace_period="PT10M", repair_action="Replace") so unhealthy instances are replaced automatically.

🤖 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 `@tilebox_iac/azure/auto_scaling_cluster.py` around lines 102 - 108, Update the
VMSS configuration’s compute.UpgradePolicyArgs in the cluster definition to
include automatic_repairs_policy using compute.AutomaticRepairsPolicyArgs with
enabled=True, grace_period="PT10M", and repair_action="Replace".

Comment on lines +19 to +31
get_access_token() {
curl -s -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.net{% if CLIENT_ID %}&client_id={{ CLIENT_ID }}{% endif %}" \
| jq -r ".access_token"
}

fetch_secret() {
local secret_url="$1"
local access_token="$2"

curl -s -H "Authorization: Bearer ${access_token}" \
"${secret_url}?api-version=7.4" \
| jq -r ".value"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the Azure cloud-init template.
git ls-files 'tilebox_iac/azure/cloud-init.yaml' 'tilebox_iac/**/cloud-init.yaml' | sed -n '1,20p'

echo '--- outline ---'
ast-grep outline tilebox_iac/azure/cloud-init.yaml --view expanded

echo '--- relevant lines ---'
nl -ba tilebox_iac/azure/cloud-init.yaml | sed -n '1,220p'

Repository: tilebox/tilebox-iac

Length of output: 383


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for shell safety flags and how failures are handled in related cloud-init templates.
rg -n --hidden --glob 'tilebox_iac/**/*.yaml' --glob '!**/.git/**' 'set -e|set -u|pipefail|curl -s|fail-with-body|retry|jq -r ".value"|ExecStartPre|systemd' tilebox_iac

Repository: tilebox/tilebox-iac

Length of output: 2296


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the surrounding service/unit generation if present.
rg -n --hidden --glob 'tilebox_iac/**' 'ExecStartPre|ExecStart|systemd|health probe|Application Health|ManagedIdentity|vault.azure.net' tilebox_iac

Repository: tilebox/tilebox-iac

Length of output: 3376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the Azure cloud-init template around the secret-fetch logic and the service unit.
sed -n '1,170p' tilebox_iac/azure/cloud-init.yaml | cat -n

Repository: tilebox/tilebox-iac

Length of output: 5201


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the Azure script body and how its output is consumed.
sed -n '1,150p' tilebox_iac/azure/cloud-init.yaml | python3 - <<'PY'
import sys
for i, line in enumerate(sys.stdin, 1):
    if 10 <= i <= 45 or 85 <= i <= 130:
        print(f"{i:4d}: {line}", end="")
PY

Repository: tilebox/tilebox-iac

Length of output: 161


🌐 Web query:

Azure IMDS token endpoint error response JSON access_token missing jq null Key Vault secret endpoint error response JSON value missing

💡 Result:

When interacting with Azure REST APIs like IMDS or Key Vault, a missing JSON field (such as access_token or value) in a response is typically the result of an error state rather than a standard success response [1][2]. Azure IMDS Token Endpoint A successful request to the Azure Instance Metadata Service (IMDS) managed identity token endpoint (http://169.254.169.254/metadata/identity/oauth2/token) returns a JSON object containing the access_token [1]. If the access_token field is missing or null, it indicates the token request failed [3]. Common causes include: - Missing Metadata header: The Metadata: true header is mandatory to prevent Server-Side Request Forgery (SSRF) attacks [1]. - Missing or invalid identity: The resource has no assigned identity or the requested resource audience (via the resource parameter) is incorrect [1][2]. - Insufficient permissions: The identity lacks the required role assignments to access the target service [1]. To handle this in scripts using jq, you should verify the token exists before proceeding: TOKEN=$(curl -s -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?..." | jq -r '.access_token') if [[ -z "$TOKEN" || "$TOKEN" == "null" ]]; then echo "Error: Failed to obtain token" exit 1 fi Azure Key Vault Secret Endpoint When a request to the Azure Key Vault secret endpoint returns a missing value field, it is also typically because the request failed, often returning a 4xx error (e.g., 401 Unauthorized or 403 Forbidden) [2][4]. Azure Key Vault does not return the secret value in an error response; instead, it returns a JSON object containing an error code and message [5][4]. Example error response structure: { "error": { "code": "Forbidden", "message": "The user does not have secrets get permission..." } } If your automation (such as Ansible or a script) attempts to access secret_res.json["value"] when an error occurs, it will trigger a KeyError or null value error [2]. Always check the HTTP status code or verify the presence of the error key before attempting to access the value field [4]. If the jq utility is unavailable, consider using | python -m json.tool for debugging [6].

Citations:


Fail on missing IMDS/Key Vault fields tilebox_iac/azure/cloud-init.yaml:19-31
curl -s | jq -r can turn error responses into null, which writes invalid values into /tmp/secrets.env and lets the runner start with broken credentials. Use curl --fail-with-body and/or jq -e with explicit null checks before appending.

🤖 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 `@tilebox_iac/azure/cloud-init.yaml` around lines 19 - 31, Update
get_access_token and fetch_secret in cloud-init.yaml to fail when IMDS or Key
Vault requests return errors or when the expected token/value fields are missing
or null. Use curl’s failure mode and jq validation, then ensure invalid results
are rejected before secrets are appended to /tmp/secrets.env or the runner
starts.

@snamber snamber closed this Jul 15, 2026
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.

1 participant