env

package
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 5, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package env provides environment variable utilities for Azure Developer CLI (azd) extensions.

This package includes:

  • Key Vault reference resolution (ResolveMap, ResolveSlice)
  • Format conversion (MapToSlice, SliceToMap)
  • Pattern-based extraction (FilterByPrefix, ExtractPattern)
  • Service name normalization (NormalizeServiceName)

Key Vault Resolution

Use ResolveMap to resolve Azure Key Vault references in environment maps:

import (
	"github.com/jongio/azd-core/env"
	"github.com/jongio/azd-core/keyvault"
)

resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
	return err
}

envMap := map[string]string{
	"DATABASE_URL": "postgres://localhost/db",
	"API_KEY": "@Microsoft.KeyVault(VaultName=myvault;SecretName=api-key)",
}

resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
	return err
}
// resolved["API_KEY"] now contains the actual secret value from Key Vault

Pattern-Based Extraction

Extract environment variables matching specific patterns:

// Filter by prefix (case-insensitive)
azureVars := env.FilterByPrefix(envVars, "AZURE_")
// Returns: {"AZURE_TENANT_ID": "xyz", "AZURE_CLIENT_ID": "abc"}

// Extract SERVICE_*_URL with normalization
serviceURLs := env.ExtractPattern(envVars, env.PatternOptions{
	Prefix:       "SERVICE_",
	Suffix:       "_URL",
	TrimPrefix:   true,
	TrimSuffix:   true,
	Transform:    env.NormalizeServiceName,
})
// Returns: {"my-api": "https://...", "web-app": "https://..."}

Service Name Normalization

Convert environment variable naming to service naming conventions:

serviceName := env.NormalizeServiceName("MY_API_SERVICE")
// Returns: "my-api-service"

This is useful for converting uppercase underscore-separated names (common in environment variables) to lowercase hyphen-separated names (common in service identifiers, DNS labels, and container names).

Supported Key Vault Reference Formats

  • @Microsoft.KeyVault(SecretUri=https://...)
  • @Microsoft.KeyVault(VaultName=...;SecretName=...;SecretVersion=...)
  • akvs://<subscription-id>/<vault-name>/<secret-name>[/<version>]

Authentication

Key Vault resolution uses azidentity.DefaultAzureCredential, which supports:

  • Environment variables (AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET)
  • Managed identity (Azure VM, App Service, Container Apps)
  • Azure CLI (az login)
  • Azure PowerShell
  • Interactive browser authentication

Error Handling

By default, resolution continues even if individual references fail (warnings are collected). Use StopOnError to fail fast:

opts := keyvault.ResolveEnvironmentOptions{StopOnError: true}
resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, opts)
if err != nil {
	// First error encountered
}

Package env provides environment variable resolution utilities with Azure Key Vault integration.

This package makes it easy for consumers (like azd-app and azd-exec) to resolve Azure Key Vault references in environment variables. It provides adapter functions to work with both map[string]string and []string representations of environment variables.

Usage with Environment Maps

Use ResolveMap when working with environment maps:

resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
	// handle error
}

envMap := map[string]string{
	"DATABASE_URL": "postgres://localhost/db",
	"API_KEY": "@Microsoft.KeyVault(VaultName=myvault;SecretName=api-key)",
}

resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
	// handle error
}
for _, w := range warnings {
	// log warning: w.Key, w.Err
}
// resolved["API_KEY"] now contains the actual secret value from Key Vault

Usage with Environment Slices

Use ResolveSlice when working with KEY=VALUE slices (e.g., from os.Environ()):

resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
	// handle error
}

envSlice := os.Environ() // or []string{"KEY=value", ...}
resolved, warnings, err := env.ResolveSlice(ctx, envSlice, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
	// handle error
}
// Use resolved with exec.Cmd: cmd.Env = resolved

Error Handling Options

By default, resolution continues even if individual references fail (warnings are collected). Use StopOnError to fail fast:

opts := keyvault.ResolveEnvironmentOptions{StopOnError: true}
resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, opts)
if err != nil {
	// Resolution failed, warnings contains details
}

Supported Key Vault Reference Formats

The package supports three Key Vault reference formats:

Helper Functions

The package also provides utility functions for working with environment variables:

  • MapToSlice: Convert map[string]string to []string (KEY=VALUE format)
  • SliceToMap: Convert []string to map[string]string (skips malformed entries)
  • HasKeyVaultReferences: Check if any Key Vault references exist

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractPattern added in v0.3.0

func ExtractPattern(envVars map[string]string, opts PatternOptions) map[string]string

ExtractPattern extracts environment variables matching prefix/suffix with key transformation. Pattern matching is case-insensitive. Returns a new map with transformed keys.

Example:

envVars := map[string]string{
	"SERVICE_API_URL": "https://api.example.com",
	"SERVICE_WEB_URL": "https://web.example.com",
	"SERVICE_DB_HOST": "db.example.com",
}

// Extract all SERVICE_*_URL variables and normalize service names
urls := env.ExtractPattern(envVars, env.PatternOptions{
	Prefix:     "SERVICE_",
	Suffix:     "_URL",
	TrimPrefix: true,
	TrimSuffix: true,
	Transform:  func(s string) string { return strings.ToLower(strings.ReplaceAll(s, "_", "-")) },
})
// Returns: {"api": "https://api.example.com", "web": "https://web.example.com"}

func FilterByPrefix added in v0.3.0

func FilterByPrefix(envVars map[string]string, prefix string) map[string]string

FilterByPrefix returns environment variables matching a prefix. The prefix matching is case-insensitive for keys. Returns a new map containing only the matching entries.

Example:

envVars := map[string]string{
	"AZURE_TENANT_ID": "xyz",
	"AZURE_CLIENT_ID": "abc",
	"DATABASE_URL": "postgres://...",
}
azureVars := env.FilterByPrefix(envVars, "AZURE_")
// Returns: {"AZURE_TENANT_ID": "xyz", "AZURE_CLIENT_ID": "abc"}

func FilterByPrefixSlice added in v0.3.0

func FilterByPrefixSlice(envSlice []string, prefix string) []string

FilterByPrefixSlice returns KEY=VALUE pairs matching a prefix. The prefix matching is case-insensitive for keys. Returns a new slice containing only the matching entries. Malformed entries (without "=") are skipped.

Example:

envSlice := []string{
	"AZURE_TENANT_ID=xyz",
	"AZURE_CLIENT_ID=abc",
	"DATABASE_URL=postgres://...",
}
azureVars := env.FilterByPrefixSlice(envSlice, "AZURE_")
// Returns: ["AZURE_TENANT_ID=xyz", "AZURE_CLIENT_ID=abc"]

func GetAzdEnvironmentValues added in v0.4.0

func GetAzdEnvironmentValues(ctx context.Context, envName string) (map[string]string, error)

GetAzdEnvironmentValues retrieves all environment variables from the specified azd environment without setting them. This is useful when you need the values but don't want to modify the current process environment.

func HasKeyVaultReferences

func HasKeyVaultReferences(envVars []string) bool

HasKeyVaultReferences quickly checks for any key vault formatted values.

func LoadAzdEnvironment added in v0.4.0

func LoadAzdEnvironment(ctx context.Context, envName string) error

LoadAzdEnvironment loads all environment variables from the specified azd environment by calling 'azd env get-values' and sets them in the current process.

This ensures that when the -e flag is used, the correct environment values are loaded.

WORKAROUND: This is a workaround for a limitation in the azd extension framework. Ideally, azd should honor the -e flag before invoking the extension and inject the correct environment variables. However, currently azd injects the default environment from config.json, then passes the -e flag to the extension. This forces us to manually reload the environment using 'azd env get-values'.

func MapToSlice

func MapToSlice(env map[string]string) []string

MapToSlice converts an env map into KEY=VALUE entries.

func NormalizeServiceName added in v0.3.0

func NormalizeServiceName(envVarName string) string

NormalizeServiceName converts environment variable naming to service naming. Converts uppercase underscore-separated names to lowercase hyphen-separated names. Commonly used with ExtractPattern to normalize service names from environment variables.

Example:

name := env.NormalizeServiceName("MY_API_SERVICE")
// Returns: "my-api-service"

name = env.NormalizeServiceName("WEB_APP")
// Returns: "web-app"

func ParseKeyValueFormat added in v0.4.0

func ParseKeyValueFormat(output []byte) (map[string]string, error)

ParseKeyValueFormat parses output in "KEY=value" format (one per line). Handles quoted values and skips empty lines and comments.

func Resolve

Resolve applies a key vault resolver to the provided env map if needed.

func ResolveMap

ResolveMap applies the Key Vault resolver to an environment map. It converts the map to a slice, resolves any Key Vault references, and returns a new map with the resolved values. If resolver is nil or no Key Vault references are found, the original map is returned (as a copy).

This is the primary helper for consumers like azd-app and azd-exec that work with environment maps (e.g., from os.Environ() converted to a map).

Example usage:

resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
	// handle error
}
envMap := map[string]string{
	"DATABASE_URL": "postgres://localhost/db",
	"API_KEY": "@Microsoft.KeyVault(VaultName=myvault;SecretName=api-key)",
}
resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
	// handle error
}
for _, w := range warnings {
	// log warning: w.Key, w.Err
}
// resolved["API_KEY"] now contains the actual secret value

func ResolveSlice

func ResolveSlice(ctx context.Context, envSlice []string, resolver Resolver, opts keyvault.ResolveEnvironmentOptions) ([]string, []keyvault.KeyVaultResolutionWarning, error)

ResolveSlice applies the Key Vault resolver to an environment slice. It takes KEY=VALUE entries, resolves any Key Vault references, and returns a new slice with the resolved values. If resolver is nil or no Key Vault references are found, the original slice is returned (as a copy).

This is useful for consumers that work directly with environment slices (e.g., from os.Environ() or for passing to exec.Cmd.Env).

Example usage:

resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
	// handle error
}
envSlice := []string{
	"DATABASE_URL=postgres://localhost/db",
	"API_KEY=@Microsoft.KeyVault(VaultName=myvault;SecretName=api-key)",
}
resolved, warnings, err := env.ResolveSlice(ctx, envSlice, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
	// handle error
}
for _, w := range warnings {
	// log warning: w.Key, w.Err
}
// resolved can now be used with cmd.Env = resolved

func SliceToMap

func SliceToMap(envSlice []string) map[string]string

SliceToMap converts KEY=VALUE entries into a map, skipping malformed rows.

Types

type CommandRunner added in v0.4.0

type CommandRunner interface {
	Run(ctx context.Context, name string, args ...string) ([]byte, error)
}

CommandRunner is an interface for running external commands. This allows for mocking in tests.

func SetCommandRunner added in v0.4.0

func SetCommandRunner(runner CommandRunner) CommandRunner

SetCommandRunner sets a custom command runner (useful for testing). Returns the previous runner so it can be restored.

type DefaultCommandRunner added in v0.4.0

type DefaultCommandRunner struct{}

DefaultCommandRunner uses os/exec to run commands.

func (*DefaultCommandRunner) Run added in v0.4.0

func (r *DefaultCommandRunner) Run(ctx context.Context, name string, args ...string) ([]byte, error)

Run executes a command and returns its output.

type PatternOptions added in v0.3.0

type PatternOptions struct {
	// Prefix is the required prefix for keys (e.g., "SERVICE_")
	Prefix string

	// Suffix is the optional suffix for keys (e.g., "_URL")
	Suffix string

	// TrimPrefix removes the prefix from result keys if true
	TrimPrefix bool

	// TrimSuffix removes the suffix from result keys if true
	TrimSuffix bool

	// Transform is an optional key transformation function applied after trimming
	// Example: func(s string) string { return strings.ToLower(s) }
	Transform func(string) string

	// Validator is an optional value validation function
	// If provided, only entries where Validator(value) returns true are included
	// Example: func(v string) bool { return v != "" }
	Validator func(string) bool
}

PatternOptions configures pattern-based environment variable extraction.

type Resolver

type Resolver interface {
	ResolveEnvironmentVariables(ctx context.Context, env []string, opts keyvault.ResolveEnvironmentOptions) ([]string, []keyvault.KeyVaultResolutionWarning, error)
}

Resolver abstracts key vault environment resolution to ease testing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL