azd-core

module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2026 License: MIT

README

azd-core

Go Reference Go Report Card CI codecov CodeQL govulncheck golangci-lint Go Version Platform Support

Common reusable Go modules for building Azure Developer CLI (azd) extensions and tooling.

Overview

azd-core provides shared utilities extracted from the Azure Developer CLI to support building azd extensions, custom CLI tools, and automation scripts. The goal is to enable developers to create azd-compatible tools without duplicating common logic or pulling in the entire azd runtime.

This library includes:

  • URL Validation: RFC-compliant HTTP/HTTPS URL validation and parsing
  • Environment Management: Environment variable resolution, pattern extraction, and Key Vault integration
  • File System Utilities: Atomic writes, JSON handling, secure file operations
  • Path Management: Tool discovery, PATH manipulation, installation suggestions
  • Process Utilities: Cross-platform process detection and management
  • Shell Detection: Script type detection from extensions, shebangs, and OS defaults
  • Copilot Skill Installation: Version-aware installation of agentskills.io SKILL.md files
  • Browser Launching: Secure cross-platform URL opening
  • Security Validation: Path traversal prevention, input sanitization, permission checks
  • Extension Manifests: Checks that catch extension.yaml keys azd silently ignores

Installation

go get github.com/jongio/azd-core

Or add specific packages to your go.mod:

go get github.com/jongio/azd-core/auth
go get github.com/jongio/azd-core/browser
go get github.com/jongio/azd-core/cache
go get github.com/jongio/azd-core/cliout
go get github.com/jongio/azd-core/cmdutil
go get github.com/jongio/azd-core/copilotskills
go get github.com/jongio/azd-core/editor
go get github.com/jongio/azd-core/env
go get github.com/jongio/azd-core/fileutil
go get github.com/jongio/azd-core/healthcheck
go get github.com/jongio/azd-core/httpclient
go get github.com/jongio/azd-core/keyvault
go get github.com/jongio/azd-core/logutil
go get github.com/jongio/azd-core/manifest
go get github.com/jongio/azd-core/notify
go get github.com/jongio/azd-core/pathutil
go get github.com/jongio/azd-core/progress
go get github.com/jongio/azd-core/projecttype
go get github.com/jongio/azd-core/registry
go get github.com/jongio/azd-core/security
go get github.com/jongio/azd-core/testutil
go get github.com/jongio/azd-core/urlutil
go get github.com/jongio/azd-core/version
go get github.com/jongio/azd-core/yamlutil

Documentation

Full API documentation is available at pkg.go.dev/github.com/jongio/azd-core.

Extension Development:

Migration Guides:

Packages

urlutil

URL validation and parsing utilities with RFC-compliant validation.

Key Functions:

  • Validate - Comprehensive HTTP/HTTPS URL validation using net/url.Parse
  • ValidateHTTPSOnly - Enforce HTTPS-only for production (allows localhost HTTP)
  • Parse - Parse and normalize URLs with validation
  • NormalizeScheme - Ensure URL has http:// or https:// prefix

Validation Rules:

  • Protocol must be http:// or https:// (rejects ftp://, file://, javascript://, etc.)
  • URL must have a valid host/domain (rejects "http://", "https://")
  • URL must not exceed 2048 characters (RFC 2616 practical limit)
  • Uses net/url.Parse for RFC 3986 compliant parsing
  • Whitespace is trimmed before validation

Security Features:

  • Prevents protocol injection (javascript:, file:, data: URLs)
  • Validates host presence to prevent malformed URLs
  • Length limits prevent DoS via extremely long URLs
  • HTTPS enforcement for production with localhost exception

Example:

import "github.com/jongio/azd-core/urlutil"

// Validate custom URL from configuration
if err := urlutil.Validate(customURL); err != nil {
    return fmt.Errorf("invalid custom URL: %w", err)
}

// Enforce HTTPS for production endpoints (allows localhost HTTP)
if err := urlutil.ValidateHTTPSOnly(apiEndpoint); err != nil {
    return fmt.Errorf("production endpoint must use HTTPS: %w", err)
}

// Parse and normalize URL
parsed, err := urlutil.Parse(userProvidedURL)
if err != nil {
    return err
}
fmt.Printf("Accessing: %s://%s\n", parsed.Scheme, parsed.Host)

// Add default scheme if missing
normalized := urlutil.NormalizeScheme("example.com", "https")
// Returns: "https://example.com"
testutil

Common testing utilities for writing reliable tests in azd extensions.

Key Functions:

  • CaptureOutput - Capture stdout during function execution for testing CLI commands
  • FindTestData - Locate test fixture directories with flexible path searching
  • TempDir - Create temporary directories with automatic cleanup via t.Cleanup()
  • Contains - Convenience helper for string containment checks

Features:

  • Proper test line reporting via t.Helper() in all functions
  • Automatic cleanup of temporary resources
  • Cross-platform path handling
  • Reliable stdout capture with goroutine-based reading

Example:

import "github.com/jongio/azd-core/testutil"

func TestCLICommand(t *testing.T) {
    // Capture command output
    output := testutil.CaptureOutput(t, func() error {
        return runCommand()
    })
    
    if !testutil.Contains(output, "success") {
        t.Error("expected success message")
    }
}

func TestWithFixtures(t *testing.T) {
    // Find test data directory
    fixturesDir := testutil.FindTestData(t, "tests", "fixtures")
    
    // Create temporary directory for outputs
    tmpDir := testutil.TempDir(t)
    // Automatically cleaned up after test
}
cliout

Structured CLI output formatting with cross-platform terminal support and multiple output formats.

Key Functions:

  • Success / Error / Warning / Info - Colored status messages with icons
  • Header / Section - Formatted section headers
  • Table - Simple table rendering, delegated to azdext.Output (honors JSON mode)
  • ProgressBar - Visual progress indicators
  • Confirm - Interactive yes/no prompts. Declines automatically when prompting is impossible (redirected stdin or stdout, AZD_NO_PROMPT, CI, AI agent host); assumes yes in JSON mode
  • Print - Hybrid output (JSON or formatted text)

Color: enabled only when azdext.DetectInteractive().CanColorize() reports the terminal can support it, which honors FORCE_COLOR=1 first, then any non-empty NO_COLOR, then whether stdout is a terminal. ForceColor() and NoColor() override the detection.

Output Formats:

  • FormatDefault - Human-readable text with ANSI colors and Unicode symbols
  • FormatJSON - Structured JSON for automation and scripting

Example:

import "github.com/jongio/azd-core/cliout"

// Set output format
if err := cliout.SetFormat("json"); err != nil {
    log.Fatal(err)
}

// Print status messages
cliout.Success("Deployment completed successfully")
cliout.Error("Failed to connect: %s", err)
cliout.Warning("This feature is deprecated")
cliout.Info("Processing %d items", count)

// Create tables
headers := []string{"Name", "Status", "Port"}
rows := []cliout.TableRow{
    {"Name": "web", "Status": "running", "Port": "8080"},
    {"Name": "api", "Status": "stopped", "Port": "3000"},
}
cliout.Table(headers, rows)

// Hybrid output (JSON mode or formatted)
data := map[string]interface{}{"status": "success", "count": 42}
cliout.Print(data, func() {
    cliout.Success("Processed %d items", 42)
})

// Interactive prompts
if cliout.Confirm("Do you want to continue?") {
    // User confirmed (always true in JSON mode)
}

// Orchestration mode for subcommands
cliout.SetOrchestrated(true)
// Now CommandHeader() calls are skipped
env

Environment variable utilities for converting between maps and slices, resolving references, and applying transformations.

Key Functions:

  • ResolveMap / ResolveSlice - Resolve Key Vault references in environment variables
  • MapToSlice / SliceToMap - Convert between map and slice formats
  • HasKeyVaultReferences - Detect Key Vault references in environment data
  • FilterByPrefix / FilterByPrefixSlice - Filter environment variables by prefix (case-insensitive)
  • ExtractPattern - Extract environment variables matching prefix/suffix with key transformation
  • NormalizeServiceName - Convert environment variable naming to service naming (MY_API → my-api)

Pattern Extraction Features:

  • Case-insensitive prefix/suffix matching
  • Optional prefix/suffix trimming from result keys
  • Custom key transformation functions
  • Value validation with callback functions
  • Useful for extracting service URLs, Azure variables, custom domain configs

Example:

import "github.com/jongio/azd-core/env"

// Filter by prefix (case-insensitive)
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"}

// Extract service URLs with normalization
serviceEnv := map[string]string{
    "SERVICE_MY_API_URL": "https://api.example.com",
    "SERVICE_WEB_APP_URL": "https://web.example.com",
    "SERVICE_DB_HOST": "db.example.com",
}
urls, _ := env.ExtractPattern(serviceEnv, env.PatternOptions{
    Prefix:       "SERVICE_",
    Suffix:       "_URL",
    TrimPrefix:   true,
    TrimSuffix:   true,
    KeyTransform: env.NormalizeServiceName, // MY_API → my-api
})
// Returns: {"my-api": "https://api.example.com", "web-app": "https://web.example.com"}

Key Vault Resolution:

keyvault

Azure Key Vault reference detection and resolution for environment variables.

Supported Formats:

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

Reference parsing, client construction, per-vault client caching, and secret retrieval come from azdext.KeyVaultResolver. This package adds the KEY=VALUE environment slice API and support for the versioned akvs:// form, which azdext does not parse on its own.

Features:

  • NewKeyVaultResolver uses azidentity.DefaultAzureCredential
  • NewKeyVaultResolverWithCredential accepts an azdext.TokenProvider, a sovereign cloud vault suffix, or an injected secret client for tests
  • Thread-safe per-vault client caching
  • Configurable error handling (fail-fast or graceful degradation)
  • Vault host allowlist covering the public, China, US Government, Germany, and Managed HSM endpoints, so a SecretUri cannot point at an arbitrary host
  • Failures are *azdext.KeyVaultResolveError, carrying a Reason that separates a malformed reference from a missing secret, an access denial, or a service error
fileutil

File system utilities with atomic operations, JSON handling, and secure file detection.

Key Functions:

  • AtomicWriteJSON / AtomicWriteFile - Write files atomically with retry logic
  • ReadJSON - Read JSON with graceful missing file handling
  • EnsureDir - Create directories with secure permissions (0750)
  • FileExists / FileExistsAny / FilesExistAll - File existence checks
  • HasFileWithExt / HasAnyFileWithExts - Extension-based file detection
  • ContainsText / ContainsTextInFile - Search file contents

Features:

  • Atomic writes prevent partial/corrupt files
  • Retry logic for transient filesystem errors
  • Secure permissions (directories: 0750, files: 0644)
  • Path traversal protection via security.ValidatePath
pathutil

PATH environment variable management and tool discovery utilities.

PATH lookup itself lives in azdext.LookupTool, which honors PATHEXT on Windows and therefore resolves .cmd shims such as npm, pnpm, az, and func. pathutil keeps only the parts the SDK has no equivalent for.

Key Functions:

  • RefreshPATH - Refresh PATH from system (Windows registry, Unix environment)
  • SearchToolInSystemPath - Search common installation directories
  • GetInstallSuggestion - Get installation URLs for 22+ popular tools

Features:

  • Cross-platform PATH refresh (Windows PowerShell registry read, Unix environment)
  • Common install directory search (Program Files, /usr/local/bin, Homebrew, etc.)
  • Installation suggestions for npm, python, docker, azd, and more
browser

Cross-platform browser launching with URL validation and timeout support.

Key Functions:

  • Launch - Open URL in system default browser (non-blocking)
  • ResolveTarget - Resolve browser target (default, system, none)
  • ValidTargets / IsValid - Target validation
  • GetTargetDisplayName / FormatValidTargets - Display formatting

Features:

  • Cross-platform support (Windows cmd/start, macOS open, Linux xdg-open)
  • URL validation (http/https only for security)
  • Non-blocking launch with configurable timeout
  • Context-based cancellation
  • Graceful error handling (warnings only, non-critical)
security

Security validation utilities for path traversal prevention, input sanitization, and permission checks.

Key Functions:

  • ValidatePath - Prevent path traversal attacks (detects .., resolves symlinks)
  • ValidateServiceName - Validate service names (DNS-safe, container-safe)
  • ValidatePackageManager - Allowlist-based package manager validation
  • ValidateScriptName - Reject shell metacharacters and path traversal
  • IsContainerEnvironment - Detect Codespaces, Dev Containers, Docker, Kubernetes
  • ValidateFilePermissions - Detect world-writable files (Unix only)

Features:

  • Path traversal attack prevention
  • Symbolic link resolution and validation
  • Service name validation (alphanumeric start, DNS label limits)
  • Shell metacharacter detection
  • Container environment detection
  • World-writable file detection (security warning)
copilotskills

Installs agentskills.io-compliant SKILL.md files from an embedded filesystem to ~/.copilot/skills/{name}/.

Key Functions:

  • Install - Write embedded skill files to ~/.copilot/skills/{name}/ with version-based skip logic

Features:

  • Version-based skip: reads .version file and skips if it matches (no unnecessary I/O)
  • Atomic file writes via fileutil.AtomicWriteFile
  • Name validation per agentskills.io spec (lowercase, hyphens, digits only)
  • Walks embedded embed.FS under a configurable root directory

Example:

import "github.com/jongio/azd-core/copilotskills"

//go:embed skills/my-extension
var skillFS embed.FS

func installSkills(version string) error {
    return copilotskills.Install("my-extension", version, skillFS, "skills/my-extension")
}

Usage Examples

Resolve Key Vault References in Environment
package main

import (
    "context"
    "os"

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

func main() {
    // Create resolver
    resolver, err := keyvault.NewKeyVaultResolver()
    if err != nil {
        panic(err)
    }

    // Resolve from environment map
    envMap := map[string]string{
        "DATABASE_PASSWORD": "@Microsoft.KeyVault(VaultName=myvault;SecretName=db-pass)",
        "API_ENDPOINT":      "https://api.example.com",
    }

    resolved, warnings, err := env.ResolveMap(
        context.Background(),
        envMap,
        resolver,
        keyvault.ResolveEnvironmentOptions{},
    )
    if err != nil {
        panic(err)
    }

    // Handle warnings
    for _, w := range warnings {
        os.Stderr.WriteString("warning: " + w.Err.Error() + "\n")
    }

    // Use resolved environment
    os.Setenv("DATABASE_PASSWORD", resolved["DATABASE_PASSWORD"])
}
Atomic File Writing
import "github.com/jongio/azd-core/fileutil"

// Write JSON atomically (prevents partial/corrupt files)
data := map[string]interface{}{
    "version": "1.0",
    "config":  map[string]string{"key": "value"},
}
err := fileutil.AtomicWriteJSON("config.json", data)
Tool Discovery
import (
    "fmt"
    "github.com/azure/azure-dev/cli/azd/pkg/azdext"
    "github.com/jongio/azd-core/pathutil"
)

// Find a tool in PATH
if node := azdext.LookupTool("node"); node.Found {
    fmt.Printf("Node.js found at: %s\n", node.Path)
} else {
    fmt.Println(pathutil.GetInstallSuggestion("node"))
}

// Search common system directories
if dockerPath := pathutil.SearchToolInSystemPath("docker"); dockerPath != "" {
    fmt.Printf("Docker found at: %s\n", dockerPath)
}
Secure Path Validation
import "github.com/jongio/azd-core/security"

// Validate user-provided path (prevents path traversal)
if err := security.ValidatePath(userPath); err != nil {
    return fmt.Errorf("invalid path: %w", err)
}

// Validate service name (DNS-safe, container-safe)
if err := security.ValidateServiceName(name, false); err != nil {
    return fmt.Errorf("invalid service name: %w", err)
}
Browser Launch
import (
    "github.com/jongio/azd-core/browser"
    "time"
)

// Open URL in default browser
err := browser.Launch(browser.LaunchOptions{
    URL:     "https://example.com",
    Target:  browser.TargetDefault,
    Timeout: 5 * time.Second,
})
Process Detection
import "github.com/azure/azure-dev/cli/azd/pkg/azdext"

// Check if process is running
if azdext.IsProcessRunning(pid) {
    fmt.Println("Process is running")
}

Authentication

The keyvault package uses azidentity.DefaultAzureCredential, supporting:

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

No global state is maintained, and client caching is thread-safe.

The auth package acquires Azure OAuth tokens for arbitrary REST calls.

DetectScope(url) maps a request URL to the OAuth scope its service expects, returning an empty scope for a host it does not recognize so the request is sent unauthenticated. Most of the mapping comes from azdext.ScopeDetector, extended with the services the SDK does not cover. Two services are resolved locally because a static host to scope map cannot describe them: Azure Data Explorer needs a scope derived from the cluster host, and Service Bus and Event Hubs share a DNS suffix and are told apart by the request path.

IsAzureHost(url) is the broader question of whether to authenticate at all. A host can be recognizably Azure without azd-core knowing its scope.

Token acquisition goes through AzureTokenProvider, which caches per scope, applies a request timeout, and classifies failures into AuthPermissionError, AuthCredentialUnavailableError, or AuthError. Three constructors:

  • NewAzureTokenProvider() builds a resilient credential chain that tries the azd CLI, the Azure CLI, environment variables, workload identity, and managed identity in that order, continuing past a hard failure rather than stopping at the first one the way DefaultAzureCredential does.
  • NewAzureTokenProviderForHost(ctx, client, opts) uses azdext.TokenProvider when an azd host client is supplied, so the tenant comes from the deployment context, and falls back to the chain when it is not.
  • NewAzureTokenProviderWithCredential(cred) wraps any azcore.TokenCredential.

Testing

# Run all tests
go test ./...

# Run with coverage
go test -cover ./...

# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out
go tool cover -html=coverage.out

Tests are offline-only and use mocks for Azure SDK interactions.

Contributing

See CONTRIBUTING.md for guidelines on contributing to this project.

Security

See SECURITY.md for information on reporting security vulnerabilities.

License

This project is licensed under the MIT License. See LICENSE.

Directories

Path Synopsis
Package auth provides Azure authentication token acquisition and caching.
Package auth provides Azure authentication token acquisition and caching.
Package browser provides utilities for launching URLs in the user's web browser.
Package browser provides utilities for launching URLs in the user's web browser.
Package cache provides file-based caching with TTL and version support.
Package cache provides file-based caching with TTL and version support.
Package cliout provides structured output formatting for CLI commands.
Package cliout provides structured output formatting for CLI commands.
Package cmdutil provides generic command execution utilities including running commands with timeouts, capturing output, and monitoring output line-by-line.
Package cmdutil provides generic command execution utilities including running commands with timeouts, capturing output, and monitoring output line-by-line.
Package copilotskills installs agentskills.io-compliant SKILL.md files from an embedded filesystem to ~/.copilot/skills/{name}/.
Package copilotskills installs agentskills.io-compliant SKILL.md files from an embedded filesystem to ~/.copilot/skills/{name}/.
Package covergate parses Go coverage profiles and enforces a ratchet: coverage may rise freely but may never fall below a recorded baseline.
Package covergate parses Go coverage profiles and enforces a ratchet: coverage may rise freely but may never fall below a recorded baseline.
cmd/covergate command
Command covergate enforces a coverage ratchet against a recorded baseline.
Command covergate enforces a coverage ratchet against a recorded baseline.
Package editor provides utilities for opening files in the user's preferred editor.
Package editor provides utilities for opening files in the user's preferred editor.
Package env provides environment variable utilities for Azure Developer CLI (azd) extensions.
Package env provides environment variable utilities for Azure Developer CLI (azd) extensions.
Package fileutil provides secure file system utilities for Azure Developer CLI extensions.
Package fileutil provides secure file system utilities for Azure Developer CLI extensions.
Package healthcheck provides HTTP and TCP health checking for services with configurable timeouts, failure tracking, and status reporting.
Package healthcheck provides HTTP and TCP health checking for services with configurable timeouts, failure tracking, and status reporting.
metrics
Package metrics provides Prometheus metrics instrumentation for the healthcheck package.
Package metrics provides Prometheus metrics instrumentation for the healthcheck package.
Package httpclient provides an HTTP client with auth, retry, and pagination support.
Package httpclient provides an HTTP client with auth, retry, and pagination support.
Package keyvault resolves Azure Key Vault references found in environment variables.
Package keyvault resolves Azure Key Vault references found in environment variables.
Package logutil provides a structured logging abstraction built on top of slog.
Package logutil provides a structured logging abstraction built on top of slog.
Package manifest reads and checks azd extension manifests.
Package manifest reads and checks azd extension manifests.
Package notify provides event notification and subscription utilities for broadcasting messages to registered listeners.
Package notify provides event notification and subscription utilities for broadcasting messages to registered listeners.
Package pathutil provides cross-platform PATH environment variable management utilities.
Package pathutil provides cross-platform PATH environment variable management utilities.
Package progress provides a multi-progress bar system for concurrent task tracking with spinner animations, status tracking, and terminal-aware rendering.
Package progress provides a multi-progress bar system for concurrent task tracking with spinner animations, status tracking, and terminal-aware rendering.
Package projecttype defines types for detected project frameworks and languages.
Package projecttype defines types for detected project frameworks and languages.
Package registry provides functionality for managing running service registrations using in-memory storage only.
Package registry provides functionality for managing running service registrations using in-memory storage only.
Package security provides security validation utilities for Azure Developer CLI extensions.
Package security provides security validation utilities for Azure Developer CLI extensions.
Package testutil provides common testing utilities for azd extensions.
Package testutil provides common testing utilities for azd extensions.
Package urlutil provides URL validation and parsing utilities with RFC-compliant validation.
Package urlutil provides URL validation and parsing utilities with RFC-compliant validation.
Package version provides shared version metadata and a reusable version command for azd extensions, so each extension does not reimplement the same boilerplate.
Package version provides shared version metadata and a reusable version command for azd extensions, so each extension does not reimplement the same boilerplate.
Package yamlutil provides utilities for manipulating YAML files while preserving formatting, comments, and structure.
Package yamlutil provides utilities for manipulating YAML files while preserving formatting, comments, and structure.

Jump to

Keyboard shortcuts

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