Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
- Fix: k8s scopes that have both a custom domain and additional ports now deploy, instead of failing with "Failed to build ingress template"
- Fix: k8s scopes now honor the scope-configurations provider's `security.image_pull_secrets_enabled` / `security.image_pull_secrets` over the `values.yaml` default, so non-EKS clusters (e.g. AKS pulling from ACR) no longer reference a non-existent `ecr-secret` and hit `ImagePullBackOff`

## [1.16.3] - 2026-09-08
- Add: remove resource level restriction for `elasticloadbalancing:Describe*` permissions as AWS does not support it.
Expand Down
59 changes: 38 additions & 21 deletions k8s/deployment/build_context
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,43 @@ validate_status() {
esac
}

# Resolves the image pull secrets for the pod spec into IMAGE_PULL_SECRETS.
# Priority (highest to lowest):
# 1. PULL_SECRETS env var (full JSON object, used as-is)
# 2. scope-configurations provider (security.image_pull_secrets_enabled /
# security.image_pull_secrets) — only when the provider explicitly sets the flag
# 3. IMAGE_PULL_SECRETS from values.yaml (the shipped default)
# 4. Disabled
# The flag is read with an explicit null-check instead of get_config_value because
# that helper evaluates `<path> // empty`, which turns an explicit `false` into "not set".
resolve_image_pull_secrets() {
if [[ -n "${PULL_SECRETS:-}" ]]; then
IMAGE_PULL_SECRETS=$PULL_SECRETS
return 0
fi

local provider_enabled
provider_enabled=$(echo "$CONTEXT" | jq -r \
'.providers["scope-configurations"].security.image_pull_secrets_enabled
| if . == null then "null" else tostring end')

if [ "$provider_enabled" != "null" ]; then
local provider_secrets
provider_secrets=$(get_config_value \
--provider '.providers["scope-configurations"].security.image_pull_secrets | @json' \
--default "[]"
)
IMAGE_PULL_SECRETS=$(jq -n \
--argjson enabled "$provider_enabled" \
--argjson secrets "$provider_secrets" \
'{ENABLED: $enabled, SECRETS: $secrets}')
elif [ -n "${IMAGE_PULL_SECRETS:-}" ]; then
IMAGE_PULL_SECRETS=$(echo "$IMAGE_PULL_SECRETS" | jq .)
else
IMAGE_PULL_SECRETS='{"ENABLED":false,"SECRETS":[]}'
fi
}

if ! validate_status "$SERVICE_ACTION" "$DEPLOYMENT_STATUS"; then
log error "❌ Invalid deployment status '$DEPLOYMENT_STATUS' for action '$SERVICE_ACTION'"
log error "💡 Possible causes:"
Expand Down Expand Up @@ -115,27 +152,7 @@ if [ "$DEPLOY_STRATEGY" = "rolling" ] && [ "$DEPLOYMENT_STATUS" = "running" ]; t
GREEN_REPLICAS=$(( MIN_REPLICAS > GREEN_REPLICAS ? MIN_REPLICAS : GREEN_REPLICAS ))
fi

if [[ -n "$PULL_SECRETS" ]]; then
IMAGE_PULL_SECRETS=$PULL_SECRETS
else
if [ -n "${IMAGE_PULL_SECRETS:-}" ]; then
IMAGE_PULL_SECRETS=$(echo "$IMAGE_PULL_SECRETS" | jq .)
else
PULL_SECRETS_ENABLED=$(get_config_value \
--provider '.providers["scope-configurations"].security.image_pull_secrets_enabled' \
--default "false"
)
PULL_SECRETS_LIST=$(get_config_value \
--provider '.providers["scope-configurations"].security.image_pull_secrets | @json' \
--default "[]"
)

IMAGE_PULL_SECRETS=$(jq -n \
--argjson enabled "$PULL_SECRETS_ENABLED" \
--argjson secrets "$PULL_SECRETS_LIST" \
'{ENABLED: $enabled, SECRETS: $secrets}')
fi
fi
resolve_image_pull_secrets

SCOPE_TRAFFIC_PROTOCOL=$(echo "$CONTEXT" | jq -r .scope.capabilities.protocol)

Expand Down
62 changes: 52 additions & 10 deletions k8s/deployment/tests/build_context.bats
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ setup() {

# Extract validate_status function from build_context for isolated testing
eval "$(sed -n '/^validate_status()/,/^}/p' "$PROJECT_ROOT/k8s/deployment/build_context")"

# Extract resolve_image_pull_secrets from build_context for isolated testing
eval "$(sed -n '/^resolve_image_pull_secrets()/,/^}/p' "$PROJECT_ROOT/k8s/deployment/build_context")"
}

teardown() {
unset -f validate_status 2>/dev/null || true
unset -f validate_status resolve_image_pull_secrets 2>/dev/null || true
unset CONTEXT DEPLOY_STRATEGY POD_DISRUPTION_BUDGET_ENABLED POD_DISRUPTION_BUDGET_MAX_UNAVAILABLE 2>/dev/null || true
unset TRAFFIC_CONTAINER_IMAGE TRAFFIC_MANAGER_CONFIG_MAP IMAGE_PULL_SECRETS IAM CONTAINER_MEMORY_IN_MEMORY CONTAINER_CPU_IN_MILLICORES MAIN_TRAFFIC_MANAGER_PORT 2>/dev/null || true
unset TRAFFIC_CONTAINER_IMAGE TRAFFIC_MANAGER_CONFIG_MAP IMAGE_PULL_SECRETS PULL_SECRETS IAM CONTAINER_MEMORY_IN_MEMORY CONTAINER_CPU_IN_MILLICORES MAIN_TRAFFIC_MANAGER_PORT 2>/dev/null || true
}

# =============================================================================
Expand Down Expand Up @@ -260,17 +263,56 @@ resolve_traffic_container_version() {
}

# =============================================================================
# Image Pull Secrets Tests
# Image Pull Secrets Tests (resolve_image_pull_secrets)
# =============================================================================
@test "image pull secrets: PULL_SECRETS takes precedence over IMAGE_PULL_SECRETS" {
PULL_SECRETS='["secret1"]'
IMAGE_PULL_SECRETS="{}"
@test "resolve_image_pull_secrets: PULL_SECRETS env takes precedence over provider and default" {
export PULL_SECRETS='{"ENABLED":true,"SECRETS":["from-env"]}'
export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}'
export CONTEXT=$(echo "$CONTEXT" | jq '.providers["scope-configurations"] = {
"security": {"image_pull_secrets_enabled": true, "image_pull_secrets": ["acr-secret"]}
}')

if [[ -n "$PULL_SECRETS" ]]; then
IMAGE_PULL_SECRETS=$PULL_SECRETS
fi
resolve_image_pull_secrets

assert_json_equal "$IMAGE_PULL_SECRETS" '{"ENABLED":true,"SECRETS":["from-env"]}'
}

@test "resolve_image_pull_secrets: provider wins over the values.yaml default" {
export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}'
export CONTEXT=$(echo "$CONTEXT" | jq '.providers["scope-configurations"] = {
"security": {"image_pull_secrets_enabled": true, "image_pull_secrets": ["acr-secret"]}
}')

resolve_image_pull_secrets

assert_json_equal "$IMAGE_PULL_SECRETS" '{"ENABLED":true,"SECRETS":["acr-secret"]}'
}

@test "resolve_image_pull_secrets: provider can explicitly disable pull secrets" {
export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}'
export CONTEXT=$(echo "$CONTEXT" | jq '.providers["scope-configurations"] = {
"security": {"image_pull_secrets_enabled": false}
}')

resolve_image_pull_secrets

assert_json_equal "$IMAGE_PULL_SECRETS" '{"ENABLED":false,"SECRETS":[]}'
}

@test "resolve_image_pull_secrets: falls back to the values.yaml default when the provider is silent" {
export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}'

resolve_image_pull_secrets

assert_json_equal "$IMAGE_PULL_SECRETS" '{"ENABLED":true,"SECRETS":["ecr-secret"]}'
}

@test "resolve_image_pull_secrets: disabled when neither provider nor default is set" {
unset IMAGE_PULL_SECRETS

resolve_image_pull_secrets

assert_equal "$IMAGE_PULL_SECRETS" '["secret1"]'
assert_json_equal "$IMAGE_PULL_SECRETS" '{"ENABLED":false,"SECRETS":[]}'
}

# =============================================================================
Expand Down
Loading