diff --git a/cli/go.mod b/cli/go.mod index c71835c..07171fd 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -4,7 +4,7 @@ go 1.26.0 require ( github.com/azure/azure-dev/cli/azd v0.0.0-20260228002641-8f080b39d69b - github.com/jongio/azd-core v0.5.3 + github.com/jongio/azd-core v0.5.4 github.com/magefile/mage v1.15.0 github.com/mark3labs/mcp-go v0.43.2 github.com/spf13/cobra v1.10.2 @@ -83,12 +83,12 @@ require ( go.opentelemetry.io/otel/sdk v1.40.0 // indirect go.opentelemetry.io/otel/trace v1.40.0 // indirect go.uber.org/atomic v1.11.0 // indirect - golang.org/x/crypto v0.47.0 // indirect + golang.org/x/crypto v0.48.0 // indirect golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect - golang.org/x/net v0.49.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect - golang.org/x/text v0.33.0 // indirect + golang.org/x/net v0.51.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/term v0.40.0 // indirect + golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/grpc v1.78.0 // indirect diff --git a/cli/go.sum b/cli/go.sum index 312a953..1884a72 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -123,8 +123,8 @@ github.com/jmespath-community/go-jmespath v1.1.1 h1:bFikPhsi/FdmlZhVgSCd2jj1e7G/ github.com/jmespath-community/go-jmespath v1.1.1/go.mod h1:4gOyFJsR/Gk+05RgTKYrifT7tBPWD8Lubtb5jRrfy9I= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/jongio/azd-core v0.5.3 h1:gCPJs61kUCdRYZZq4Dy4Ncz+S+00rDr9jt5CPpMgBrE= -github.com/jongio/azd-core v0.5.3/go.mod h1:jQCP+px3Pxb3B0fyShfvSVa3KsWT1j2jGXMsPpQezlI= +github.com/jongio/azd-core v0.5.4 h1:pCGn+Q+NJ4pJFsojqf0sn5osTHW8mMRzD3O6SjnlFKc= +github.com/jongio/azd-core v0.5.4/go.mod h1:XeXQJVNJ/+GbBfsYIyDdJ6E3SHCrKlEqnv6eDVqDKQ4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= @@ -240,8 +240,8 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= -golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -249,8 +249,8 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -264,18 +264,18 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/cli/src/cmd/exec/commands/mcp.go b/cli/src/cmd/exec/commands/mcp.go index 2266adc..565d862 100644 --- a/cli/src/cmd/exec/commands/mcp.go +++ b/cli/src/cmd/exec/commands/mcp.go @@ -12,6 +12,7 @@ import ( "github.com/azure/azure-dev/cli/azd/pkg/azdext" "github.com/jongio/azd-core/azdextutil" + "github.com/jongio/azd-core/keyvault" "github.com/jongio/azd-core/security" "github.com/jongio/azd-core/shellutil" "github.com/jongio/azd-exec/cli/src/internal/version" @@ -176,7 +177,10 @@ func handleExecScript(ctx context.Context, args azdext.ToolArgs) (*mcp.CallToolR cmdArgs := buildShellArgs(shell, validPath, false, scriptArgs) cmd := exec.CommandContext(execCtx, cmdArgs[0], cmdArgs[1:]...) - cmd.Env = os.Environ() + + // Resolve Key Vault references in environment variables, matching the + // CLI execution path behavior. Continue on error (best-effort). + cmd.Env = prepareEnvironmentForMCP(ctx) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout @@ -214,7 +218,10 @@ func handleExecInline(ctx context.Context, args azdext.ToolArgs) (*mcp.CallToolR cmdArgs := buildShellArgs(shell, command, true, nil) cmd := exec.CommandContext(execCtx, cmdArgs[0], cmdArgs[1:]...) - cmd.Env = os.Environ() + + // Resolve Key Vault references in environment variables, matching the + // CLI execution path behavior. Continue on error (best-effort). + cmd.Env = prepareEnvironmentForMCP(ctx) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout @@ -283,8 +290,13 @@ func handleGetEnvironment(_ context.Context, _ azdext.ToolArgs) (*mcp.CallToolRe continue } - // Exclude known secret-bearing variable names - secretPatterns := []string{"SECRET", "PASSWORD", "KEY", "TOKEN", "CREDENTIAL", "CERTIFICATE", "CONNECTION_STRING", "CONNSTR"} + // Exclude known secret-bearing variable names. + // This denylist covers common Azure, cloud, and application secret patterns. + secretPatterns := []string{ + "SECRET", "PASSWORD", "KEY", "TOKEN", "CREDENTIAL", "CERTIFICATE", + "CONNECTION_STRING", "CONNSTR", "PAT", "SAS", "SIGNING", + "PRIVATE", "PASSPHRASE", "AUTH", + } isSecret := false upperName := strings.ToUpper(name) for _, pattern := range secretPatterns { @@ -306,6 +318,41 @@ func handleGetEnvironment(_ context.Context, _ azdext.ToolArgs) (*mcp.CallToolRe // --- Helpers --- +// prepareEnvironmentForMCP resolves Key Vault references in environment variables. +// This mirrors the CLI execution path (executor.prepareEnvironment) to ensure +// consistent behavior between CLI and MCP invocations. Operates in best-effort +// mode: if resolution fails, the original environment is returned unchanged. +func prepareEnvironmentForMCP(ctx context.Context) []string { + envVars := os.Environ() + + // Quick check: skip resolver setup if no Key Vault references are present. + hasRef := false + for _, envVar := range envVars { + if parts := strings.SplitN(envVar, "=", 2); len(parts) == 2 && keyvault.IsKeyVaultReference(parts[1]) { + hasRef = true + break + } + } + if !hasRef { + return envVars + } + + resolver, err := keyvault.NewKeyVaultResolver() + if err != nil { + // Cannot create resolver — fall back to raw environment. + fmt.Fprintf(os.Stderr, "Warning: failed to create Key Vault resolver: %v\n", err) + return envVars + } + + resolved, _, err := resolver.ResolveEnvironmentVariables(ctx, envVars, keyvault.ResolveEnvironmentOptions{StopOnError: false}) + if err != nil { + fmt.Fprintf(os.Stderr, "Warning: Key Vault resolution error: %v\n", err) + return envVars + } + + return resolved +} + type execResult struct { Stdout string `json:"stdout"` Stderr string `json:"stderr"` diff --git a/cli/src/cmd/exec/commands/version_integration_test.go b/cli/src/cmd/exec/commands/version_integration_test.go index 2c9ce68..53a5f9e 100644 --- a/cli/src/cmd/exec/commands/version_integration_test.go +++ b/cli/src/cmd/exec/commands/version_integration_test.go @@ -1,5 +1,4 @@ //go:build integration -// +build integration package commands diff --git a/cli/src/cmd/exec/main.go b/cli/src/cmd/exec/main.go index dfd60be..8c185c2 100644 --- a/cli/src/cmd/exec/main.go +++ b/cli/src/cmd/exec/main.go @@ -33,7 +33,7 @@ type scriptExecutor interface { ExecuteInline(ctx context.Context, scriptContent string) error } -var newScriptExecutor = func(config executor.Config) scriptExecutor { +var newScriptExecutor = func(config executor.Config) (scriptExecutor, error) { return executor.New(config) } @@ -75,12 +75,15 @@ Examples: } // Create executor - exec := newScriptExecutor(executor.Config{ + exec, err := newScriptExecutor(executor.Config{ Shell: shell, Interactive: interactive, StopOnKeyVaultError: stopOnKeyVaultError, Args: scriptArgs, }) + if err != nil { + return fmt.Errorf("invalid configuration: %w", err) + } // Check if input is a file or inline script // Try to resolve as file path first diff --git a/cli/src/cmd/exec/main_test.go b/cli/src/cmd/exec/main_test.go index acee522..a1740df 100644 --- a/cli/src/cmd/exec/main_test.go +++ b/cli/src/cmd/exec/main_test.go @@ -90,9 +90,9 @@ func TestRunE_DispatchesFileOrInline(t *testing.T) { defer func() { newScriptExecutor = oldNew }() fake := &fakeExecutor{} - newScriptExecutor = func(cfg executor.Config) scriptExecutor { + newScriptExecutor = func(cfg executor.Config) (scriptExecutor, error) { fake.args = append([]string{}, cfg.Args...) - return fake + return fake, nil } // Avoid changing env/cwd during Execute. @@ -150,9 +150,9 @@ func TestRunE_AllowsPassthroughArgsWithoutDoubleDash(t *testing.T) { defer func() { newScriptExecutor = oldNew }() fake := &fakeExecutor{} - newScriptExecutor = func(cfg executor.Config) scriptExecutor { + newScriptExecutor = func(cfg executor.Config) (scriptExecutor, error) { fake.args = append([]string{}, cfg.Args...) - return fake + return fake, nil } // Avoid changing env/cwd during Execute. diff --git a/cli/src/internal/executor/command_builder.go b/cli/src/internal/executor/command_builder.go index d572685..511597a 100644 --- a/cli/src/internal/executor/command_builder.go +++ b/cli/src/internal/executor/command_builder.go @@ -25,32 +25,44 @@ var validShells = map[string]bool{ // - Windows cmd: Use /c for both inline and files // - Unknown shells: Fall back to -c flag (Unix-like behavior) // +// Known shell names are normalized to lowercase for the executable binary +// to ensure correct lookup on case-sensitive filesystems. // Script arguments (e.config.Args) are appended after the script specification. func (e *Executor) buildCommand(shell, scriptOrPath string, isInline bool) *exec.Cmd { var cmdArgs []string skipAppendArgs := false - // Normalize shell name to lowercase for comparison + // Normalize shell name to lowercase for both comparison and executable name. + // This ensures correct binary lookup on case-sensitive filesystems + // (e.g., --shell BASH resolves to "bash", not "BASH"). shellLower := strings.ToLower(shell) + // Use the lowercase name for known shells; keep original for unknown shells + // (custom interpreters like "Python3" should preserve user's casing). + shellBin := shell + if validShells[shellLower] { + shellBin = shellLower + } + switch shellLower { case shellutil.ShellBash, shellutil.ShellSh, shellutil.ShellZsh: if isInline { - cmdArgs = []string{shell, "-c", scriptOrPath} + cmdArgs = []string{shellBin, "-c", scriptOrPath} } else { - cmdArgs = []string{shell, scriptOrPath} + cmdArgs = []string{shellBin, scriptOrPath} } case shellutil.ShellPwsh, shellutil.ShellPowerShell: if isInline { - cmdArgs = []string{shell, "-Command", e.buildPowerShellInlineCommand(scriptOrPath)} + cmdArgs = []string{shellBin, "-Command", e.buildPowerShellInlineCommand(scriptOrPath)} skipAppendArgs = true } else { - cmdArgs = []string{shell, "-File", scriptOrPath} + cmdArgs = []string{shellBin, "-File", scriptOrPath} } case shellutil.ShellCmd: - cmdArgs = []string{shell, "/c", scriptOrPath} + cmdArgs = []string{shellBin, "/c", scriptOrPath} default: - // Unknown shell: use Unix-like -c pattern as fallback + // Unknown shell: use Unix-like -c pattern as fallback. + // Preserve original casing for custom interpreters. if isInline { cmdArgs = []string{shell, "-c", scriptOrPath} } else { diff --git a/cli/src/internal/executor/command_builder_test.go b/cli/src/internal/executor/command_builder_test.go index 0b035d5..08a33f1 100644 --- a/cli/src/internal/executor/command_builder_test.go +++ b/cli/src/internal/executor/command_builder_test.go @@ -31,7 +31,10 @@ func TestBuildCommandWithCustomShell(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - exec := New(Config{Shell: tt.shell, Args: tt.args}) + exec, err := New(Config{Args: tt.args}) + if err != nil { + t.Fatalf("New() error: %v", err) + } cmd := exec.buildCommand(tt.shell, tt.scriptPath, false) // Check if command was built @@ -75,7 +78,10 @@ func TestBuildCommandShellVariations(t *testing.T) { for _, tt := range tests { t.Run(tt.shell, func(t *testing.T) { - exec := New(Config{Shell: tt.shell}) + exec, err := New(Config{Shell: tt.shell}) + if err != nil { + t.Fatalf("New() error: %v", err) + } cmd := exec.buildCommand(tt.shell, tt.scriptPath, false) if cmd == nil { @@ -87,7 +93,10 @@ func TestBuildCommandShellVariations(t *testing.T) { func TestBuildCommandLookPath(t *testing.T) { // Test that buildCommand creates a valid exec.Cmd - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } cmd := exec.buildCommand("cmd", "test.bat", false) // On Windows, cmd should be findable @@ -96,7 +105,7 @@ func TestBuildCommandLookPath(t *testing.T) { } // Verify we can look up the command - _, err := execLookPath(cmd.Args[0]) + _, err = execLookPath(cmd.Args[0]) if err != nil { t.Logf("Command %v not found in PATH (may be platform-specific)", cmd.Args[0]) } @@ -133,7 +142,10 @@ func TestQuotePowerShellArg(t *testing.T) { func TestBuildPowerShellInlineCommand(t *testing.T) { t.Run("no args returns script as-is", func(t *testing.T) { - e := New(Config{}) + e, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } got := e.buildPowerShellInlineCommand("Get-Date") if got != "Get-Date" { t.Errorf("got %q, want %q", got, "Get-Date") @@ -141,7 +153,10 @@ func TestBuildPowerShellInlineCommand(t *testing.T) { }) t.Run("with args joins and quotes", func(t *testing.T) { - e := New(Config{Args: []string{"arg1", "it's"}}) + e, err := New(Config{Args: []string{"arg1", "it's"}}) + if err != nil { + t.Fatalf("New() error: %v", err) + } got := e.buildPowerShellInlineCommand("cmd") want := "cmd 'arg1' 'it''s'" if got != want { diff --git a/cli/src/internal/executor/command_shell_test.go b/cli/src/internal/executor/command_shell_test.go index 2b135f4..d3de966 100644 --- a/cli/src/internal/executor/command_shell_test.go +++ b/cli/src/internal/executor/command_shell_test.go @@ -10,7 +10,10 @@ import ( ) func TestBuildCommand_Bash(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } t.Run("Inline bash", func(t *testing.T) { cmd := exec.buildCommand("bash", "echo test", true) @@ -43,7 +46,10 @@ func TestBuildCommand_Bash(t *testing.T) { } func TestBuildCommand_PowerShell(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } t.Run("Inline pwsh", func(t *testing.T) { cmd := exec.buildCommand("pwsh", "Write-Host 'test'", true) @@ -76,9 +82,12 @@ func TestBuildCommand_PowerShell(t *testing.T) { } func TestBuildCommand_PowerShellInlineArgsAreEmbedded(t *testing.T) { - exec := New(Config{ + exec, err := New(Config{ Args: []string{"sync", "--", "--skip-sync"}, }) + if err != nil { + t.Fatalf("New() error: %v", err) + } cmd := exec.buildCommand("pwsh", "pnpm", true) @@ -97,7 +106,10 @@ func TestBuildCommand_PowerShellInlineArgsAreEmbedded(t *testing.T) { } func TestBuildCommand_Cmd(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } t.Run("Inline cmd", func(t *testing.T) { cmd := exec.buildCommand("cmd", "echo test", true) @@ -124,9 +136,12 @@ func TestBuildCommand_Cmd(t *testing.T) { } func TestBuildCommand_WithArgs(t *testing.T) { - exec := New(Config{ + exec, err := New(Config{ Args: []string{"--verbose", "--output=json"}, }) + if err != nil { + t.Fatalf("New() error: %v", err) + } cmd := exec.buildCommand("bash", "script.sh", false) if len(cmd.Args) < 4 { @@ -143,7 +158,10 @@ func TestBuildCommand_WithArgs(t *testing.T) { } func TestBuildCommand_Zsh(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } t.Run("Inline zsh", func(t *testing.T) { cmd := exec.buildCommand("zsh", "echo test", true) @@ -167,7 +185,10 @@ func TestBuildCommand_Zsh(t *testing.T) { } func TestBuildCommand_Sh(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } cmd := exec.buildCommand("sh", "script.sh", false) if cmd.Args[0] != "sh" { @@ -176,7 +197,10 @@ func TestBuildCommand_Sh(t *testing.T) { } func TestBuildCommand_CustomShell(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } t.Run("Inline custom shell", func(t *testing.T) { cmd := exec.buildCommand("python3", "print('test')", true) @@ -200,17 +224,22 @@ func TestBuildCommand_CustomShell(t *testing.T) { } func TestBuildCommand_CaseInsensitiveShellNames(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } tests := []struct { shell string expected string }{ - {"BASH", "BASH"}, - {"Bash", "Bash"}, - {"PWSH", "PWSH"}, - {"PowerShell", "PowerShell"}, - {"CMD", "CMD"}, + // Known shells are normalized to lowercase for correct binary lookup + // on case-sensitive filesystems. + {"BASH", "bash"}, + {"Bash", "bash"}, + {"PWSH", "pwsh"}, + {"PowerShell", "powershell"}, + {"CMD", "cmd"}, } for _, tt := range tests { @@ -403,7 +432,10 @@ func TestBuildCommand(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - exec := New(Config{Shell: tt.shell, Args: tt.args}) + exec, err := New(Config{Shell: tt.shell, Args: tt.args}) + if err != nil { + t.Fatalf("New() error: %v", err) + } cmd := exec.buildCommand(tt.shell, tt.scriptPath, tt.isInline) if cmd.Path == "" { diff --git a/cli/src/internal/executor/execute_test.go b/cli/src/internal/executor/execute_test.go index 1e29422..b66c20f 100644 --- a/cli/src/internal/executor/execute_test.go +++ b/cli/src/internal/executor/execute_test.go @@ -7,9 +7,12 @@ import ( ) func TestExecuteWithInteractiveMode(t *testing.T) { - exec := New(Config{ + exec, err := New(Config{ Interactive: true, }) + if err != nil { + t.Fatalf("New() error: %v", err) + } if !exec.config.Interactive { t.Error("Interactive mode not set") @@ -17,9 +20,12 @@ func TestExecuteWithInteractiveMode(t *testing.T) { } func TestExecuteWithCustomShell(t *testing.T) { - exec := New(Config{ + exec, err := New(Config{ Shell: "bash", }) + if err != nil { + t.Fatalf("New() error: %v", err) + } if exec.config.Shell != "bash" { t.Errorf("Shell = %v, want bash", exec.config.Shell) @@ -28,16 +34,22 @@ func TestExecuteWithCustomShell(t *testing.T) { func TestExecuteError(t *testing.T) { t.Run("Nonexistent script", func(t *testing.T) { - exec := New(Config{}) - err := exec.Execute(context.Background(), "nonexistent-script.sh") + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } + err = exec.Execute(context.Background(), "nonexistent-script.sh") if err == nil { t.Error("Expected error for nonexistent script, got nil") } }) t.Run("Empty script path", func(t *testing.T) { - exec := New(Config{}) - err := exec.Execute(context.Background(), "") + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } + err = exec.Execute(context.Background(), "") if err == nil { t.Error("Expected error for empty script path, got nil") } @@ -49,7 +61,10 @@ func TestExecuteError(t *testing.T) { func TestExecuteWithArguments(t *testing.T) { args := []string{"arg1", "arg2", "arg3"} - exec := New(Config{Args: args}) + exec, err := New(Config{Args: args}) + if err != nil { + t.Fatalf("New() error: %v", err) + } if len(exec.config.Args) != 3 { t.Errorf("Args length = %v, want 3", len(exec.config.Args)) diff --git a/cli/src/internal/executor/executor.go b/cli/src/internal/executor/executor.go index 2a13662..bb62c68 100644 --- a/cli/src/internal/executor/executor.go +++ b/cli/src/internal/executor/executor.go @@ -61,14 +61,13 @@ type Executor struct { } // New creates a new script executor with the given configuration. -// Returns a configured Executor ready to execute scripts. -// The config is validated before creating the executor. -func New(config Config) *Executor { - // Validate config early to catch errors before execution. - // Note: We don't return an error to maintain backward compatibility, - // but validation happens here to fail fast on invalid shells. - _ = config.Validate() - return &Executor{config: config} +// Returns a configured Executor ready to execute scripts, or an error +// if the configuration is invalid (e.g., unknown shell name). +func New(config Config) (*Executor, error) { + if err := config.Validate(); err != nil { + return nil, err + } + return &Executor{config: config}, nil } // Execute runs a script file with azd context. @@ -91,10 +90,9 @@ func (e *Executor) Execute(ctx context.Context, scriptPath string) error { return &ValidationError{Field: "scriptPath", Reason: fmt.Sprintf("invalid path: %v", err)} } - // Check for path traversal attempts (after getting absolute path) - if strings.Contains(filepath.ToSlash(absPath), "/../") { - return &ValidationError{Field: "scriptPath", Reason: "path traversal not allowed"} - } + // Note: filepath.Abs resolves all ".." components, so explicit traversal + // checks are unnecessary here. The CLI path is user-trusted (direct invocation). + // The MCP path uses security.ValidatePathWithinBases for containment enforcement. // Ensure script exists before attempting to execute it info, err := os.Stat(absPath) diff --git a/cli/src/internal/executor/executor_coverage_test.go b/cli/src/internal/executor/executor_coverage_test.go index 205f1eb..a77928c 100644 --- a/cli/src/internal/executor/executor_coverage_test.go +++ b/cli/src/internal/executor/executor_coverage_test.go @@ -13,7 +13,10 @@ import ( ) func TestExecute_FileValidation(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } t.Run("Empty script path", func(t *testing.T) { err := exec.Execute(context.Background(), "") @@ -47,7 +50,10 @@ func TestExecute_FileValidation(t *testing.T) { } func TestExecuteInline_Validation(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } t.Run("Empty script content", func(t *testing.T) { err := exec.ExecuteInline(context.Background(), "") @@ -68,7 +74,10 @@ func TestExecuteInline_Validation(t *testing.T) { } func TestPrepareEnvironment(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } t.Run("No Key Vault references", func(t *testing.T) { // Set up environment without KV references @@ -123,7 +132,10 @@ func TestPrepareEnvironment(t *testing.T) { } func TestHasKeyVaultReferences(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } tests := []struct { name string @@ -168,7 +180,10 @@ func TestHasKeyVaultReferences(t *testing.T) { } func TestLogDebugInfo(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } // Test doesn't crash and produces output t.Run("Inline script", func(t *testing.T) { @@ -181,7 +196,10 @@ func TestLogDebugInfo(t *testing.T) { } func TestRunCommand_ErrorHandling(t *testing.T) { - exec := New(Config{}) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } shell := "bash" exitCmd := "exit 1" @@ -232,8 +250,11 @@ func TestExecutorWithDebugMode(t *testing.T) { _ = os.Setenv("AZD_SCRIPT_DEBUG", "true") - exec := New(Config{}) - err := exec.ExecuteInline(context.Background(), "echo 'debug test'") + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } + err = exec.ExecuteInline(context.Background(), "echo 'debug test'") if err != nil { t.Errorf("Unexpected error in debug mode: %v", err) } @@ -253,20 +274,26 @@ func TestExecutorWithArgs(t *testing.T) { t.Skip("Test script not found, skipping") } - exec := New(Config{ + exec, err := New(Config{ Args: args, }) + if err != nil { + t.Fatalf("New() error: %v", err) + } - err := exec.Execute(context.Background(), scriptPath) + err = exec.Execute(context.Background(), scriptPath) if err != nil { t.Logf("Script execution error (may be expected): %v", err) } } func TestExecutorInteractiveMode(t *testing.T) { - exec := New(Config{ + exec, err := New(Config{ Interactive: true, }) + if err != nil { + t.Fatalf("New() error: %v", err) + } // Just verify the config is set - can't easily test actual interactive behavior if !exec.config.Interactive { @@ -276,8 +303,11 @@ func TestExecutorInteractiveMode(t *testing.T) { // TestExecute_DirectoryPath verifies that executing a directory returns an error. func TestExecute_DirectoryPath(t *testing.T) { - exec := New(Config{}) - err := exec.Execute(context.Background(), t.TempDir()) + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } + err = exec.Execute(context.Background(), t.TempDir()) if err == nil { t.Error("Expected error for directory path") } @@ -302,8 +332,11 @@ func TestPrepareEnvironment_StopOnKeyVaultError(t *testing.T) { os.Clearenv() _ = os.Setenv("KV_VAR", "@Microsoft.KeyVault(VaultName=test;SecretName=secret)") - exec := New(Config{StopOnKeyVaultError: true}) - _, _, err := exec.prepareEnvironment(context.Background()) + exec, err := New(Config{StopOnKeyVaultError: true}) + if err != nil { + t.Fatalf("New() error: %v", err) + } + _, _, err = exec.prepareEnvironment(context.Background()) // With StopOnKeyVaultError=true and no real Azure credentials, we expect an error // (either resolver creation fails or resolution fails) if err != nil { @@ -337,7 +370,10 @@ func TestPrepareEnvironment_ResolverCreationError(t *testing.T) { } t.Run("continue on error mode", func(t *testing.T) { - exec := New(Config{StopOnKeyVaultError: false}) + exec, err := New(Config{StopOnKeyVaultError: false}) + if err != nil { + t.Fatalf("New() error: %v", err) + } envVars, warnings, err := exec.prepareEnvironment(context.Background()) if err != nil { t.Fatalf("expected no error in continue mode, got: %v", err) @@ -351,8 +387,11 @@ func TestPrepareEnvironment_ResolverCreationError(t *testing.T) { }) t.Run("stop on error mode", func(t *testing.T) { - exec := New(Config{StopOnKeyVaultError: true}) - _, _, err := exec.prepareEnvironment(context.Background()) + exec, err := New(Config{StopOnKeyVaultError: true}) + if err != nil { + t.Fatalf("New() error: %v", err) + } + _, _, err = exec.prepareEnvironment(context.Background()) if err == nil { t.Error("expected error in stop-on-error mode") } @@ -406,7 +445,10 @@ func TestNewExecutor(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - exec := New(tt.config) + exec, err := New(tt.config) + if err != nil { + t.Fatalf("New() error: %v", err) + } if exec == nil { t.Error("New() returned nil") return diff --git a/cli/src/internal/executor/executor_test.go b/cli/src/internal/executor/executor_test.go index 699531f..1d38eee 100644 --- a/cli/src/internal/executor/executor_test.go +++ b/cli/src/internal/executor/executor_test.go @@ -1,5 +1,4 @@ //go:build integration -// +build integration package executor @@ -48,11 +47,14 @@ func TestExecuteIntegration(t *testing.T) { t.Fatal(err) } - exec := New(Config{ + exec, err := New(Config{ Shell: tt.shell, }) + if err != nil { + t.Fatalf("New() error: %v", err) + } - err := exec.Execute(context.Background(), scriptPath) + err = exec.Execute(context.Background(), scriptPath) if (err != nil) != tt.wantErr { t.Errorf("Execute() error = %v, wantErr %v", err, tt.wantErr) } @@ -123,11 +125,14 @@ func TestExecuteInlineIntegration(t *testing.T) { t.Skip("Skipping test on this platform") } - exec := New(Config{ + exec, err := New(Config{ Shell: tt.shell, }) + if err != nil { + t.Fatalf("New() error: %v", err) + } - err := exec.ExecuteInline(context.Background(), tt.script) + err = exec.ExecuteInline(context.Background(), tt.script) if (err != nil) != tt.wantErr { t.Errorf("ExecuteInline() error = %v, wantErr %v", err, tt.wantErr) } @@ -137,8 +142,11 @@ func TestExecuteInlineIntegration(t *testing.T) { // TestExecuteInlineEmptyScript tests that empty inline scripts return an error. func TestExecuteInlineEmptyScript(t *testing.T) { - exec := New(Config{}) - err := exec.ExecuteInline(context.Background(), "") + exec, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } + err = exec.ExecuteInline(context.Background(), "") if err == nil { t.Error("ExecuteInline() with empty script should return an error") } diff --git a/cli/src/internal/executor/keyvault_integration_test.go b/cli/src/internal/executor/keyvault_integration_test.go index 94f5209..adabb5d 100644 --- a/cli/src/internal/executor/keyvault_integration_test.go +++ b/cli/src/internal/executor/keyvault_integration_test.go @@ -1,5 +1,4 @@ //go:build integration -// +build integration package executor @@ -163,8 +162,11 @@ func TestExecutorWithKeyVaultReferences(t *testing.T) { os.Setenv("MY_KV_SECRET", kvRef) defer os.Unsetenv("MY_KV_SECRET") - executor := New(Config{}) - err := executor.Execute(context.Background(), scriptPath) + executor, err := New(Config{}) + if err != nil { + t.Fatalf("New() error: %v", err) + } + err = executor.Execute(context.Background(), scriptPath) // We expect this to work if Azure credentials are available if err != nil { diff --git a/package.json b/package.json index 5446560..44b829b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,6 @@ "test:all": "pnpm test" }, "dependencies": { - "@jongio/azd-web-core": "^2.1.0" + "@jongio/azd-web-core": "^2.4.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 749a39e..a19f0af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@jongio/azd-web-core': - specifier: ^2.1.0 - version: 2.1.0(astro@5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))(tailwindcss@4.1.18) + specifier: ^2.4.1 + version: 2.4.1(astro@5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))(prettier@3.8.1)(tailwindcss@4.1.18)(typescript@5.9.3) web: dependencies: @@ -18,8 +18,8 @@ importers: specifier: ^4.3.13 version: 4.3.13(astro@5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)) '@jongio/azd-web-core': - specifier: ^2.4.0 - version: 2.4.0(astro@5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))(tailwindcss@4.1.18) + specifier: ^2.4.1 + version: 2.4.1(astro@5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))(prettier@3.8.1)(tailwindcss@4.1.18)(typescript@5.9.3) astro: specifier: ^5.17.1 version: 5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) @@ -54,12 +54,30 @@ importers: packages: + '@astrojs/check@0.9.6': + resolution: {integrity: sha512-jlaEu5SxvSgmfGIFfNgcn5/f+29H61NJzEMfAZ82Xopr4XBchXB1GVlcJsE+elUlsYSbXlptZLX+JMG3b/wZEA==} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + '@astrojs/compiler@2.13.0': resolution: {integrity: sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw==} '@astrojs/internal-helpers@0.7.5': resolution: {integrity: sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==} + '@astrojs/language-server@2.16.3': + resolution: {integrity: sha512-yO5K7RYCMXUfeDlnU6UnmtnoXzpuQc0yhlaCNZ67k1C/MiwwwvMZz+LGa+H35c49w5QBfvtr4w4Zcf5PcH8uYA==} + hasBin: true + peerDependencies: + prettier: ^3.0.0 + prettier-plugin-astro: '>=0.11.0' + peerDependenciesMeta: + prettier: + optional: true + prettier-plugin-astro: + optional: true + '@astrojs/markdown-remark@6.3.10': resolution: {integrity: sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==} @@ -77,6 +95,9 @@ packages: resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + '@astrojs/yaml2ts@0.2.2': + resolution: {integrity: sha512-GOfvSr5Nqy2z5XiwqTouBBpy5FyI6DEe+/g/Mk5am9SjILN1S5fOEvYK0GuWHg98yS/dobP4m8qyqw/URW35fQ==} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -102,6 +123,27 @@ packages: resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} engines: {node: '>=14'} + '@emmetio/abbreviation@2.3.3': + resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} + + '@emmetio/css-abbreviation@2.1.8': + resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} + + '@emmetio/css-parser@0.4.1': + resolution: {integrity: sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==} + + '@emmetio/html-matcher@1.3.0': + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + + '@emmetio/scanner@1.0.4': + resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} + + '@emmetio/stream-reader-utils@0.1.0': + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + + '@emmetio/stream-reader@2.2.0': + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + '@emnapi/runtime@1.8.1': resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} @@ -566,14 +608,8 @@ packages: cpu: [x64] os: [win32] - '@jongio/azd-web-core@2.1.0': - resolution: {integrity: sha512-K0PihIeyohfrBukpNV9CSI2TkE/9HklkDP1LtCC2cEZ1lbDNXzSOis8xjpUlTpJLFyYWNHjDqDZOkB45qKS3Aw==, tarball: https://npm.pkg.github.com/download/@jongio/azd-web-core/2.1.0/9c6490bf909a72091525a0cf12d79f6481df7f0a} - peerDependencies: - astro: '>=5.0.0' - tailwindcss: '>=4.0.0' - - '@jongio/azd-web-core@2.4.0': - resolution: {integrity: sha512-qxT3l/Uf1wMwbOuClXDX4oHRGzvSHrWy+PpDkoAgQZvIoAQwxIDZTvwSYqMCLRRTQGePjiEzLNEVpl7tTwHKBg==, tarball: https://npm.pkg.github.com/download/@jongio/azd-web-core/2.4.0/a48699c64efe80f3645d6931a0635b3a9ee4e6a8} + '@jongio/azd-web-core@2.4.1': + resolution: {integrity: sha512-lkzo2YnwRIUJjqVgB3DJ4dLjODgww/o1JBIRGKlTLgwJo3XvWkpo72fNO5a7bkdyNQg6nfe7OGnmLOayE6OhgA==, tarball: https://npm.pkg.github.com/download/@jongio/azd-web-core/2.4.1/46b9ae2f978eb0c52ce2adabe536dfbf5ea483dc} peerDependencies: astro: '>=5.0.0' tailwindcss: '>=4.0.0' @@ -886,6 +922,32 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@volar/kit@2.4.28': + resolution: {integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==} + peerDependencies: + typescript: '*' + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/language-server@2.4.28': + resolution: {integrity: sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==} + + '@volar/language-service@2.4.28': + resolution: {integrity: sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vscode/emmet-helper@2.11.0': + resolution: {integrity: sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==} + + '@vscode/l10n@0.0.18': + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -896,6 +958,17 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -907,6 +980,10 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -1001,6 +1078,10 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chokidar@5.0.0: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} @@ -1013,6 +1094,10 @@ packages: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -1020,6 +1105,13 @@ packages: collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -1134,6 +1226,9 @@ packages: electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + emmet@2.4.11: + resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} + emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -1212,6 +1307,12 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1245,6 +1346,10 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.4.0: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} @@ -1366,10 +1471,23 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + jsonc-parser@2.3.1: + resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} @@ -1440,6 +1558,9 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -1629,6 +1750,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1693,6 +1817,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + piccolore@0.1.3: resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} @@ -1734,6 +1861,11 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + prismjs@1.30.0: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} @@ -1748,6 +1880,10 @@ packages: radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + readdirp@5.0.0: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} @@ -1812,6 +1948,20 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + request-light@0.5.8: + resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} + + request-light@0.7.0: + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -1942,6 +2092,12 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + typesafe-path@0.2.2: + resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==} + + typescript-auto-import-cache@0.3.6: + resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -2126,6 +2282,98 @@ packages: vite: optional: true + volar-service-css@0.0.68: + resolution: {integrity: sha512-lJSMh6f3QzZ1tdLOZOzovLX0xzAadPhx8EKwraDLPxBndLCYfoTvnNuiFFV8FARrpAlW5C0WkH+TstPaCxr00Q==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-emmet@0.0.68: + resolution: {integrity: sha512-nHvixrRQ83EzkQ4G/jFxu9Y4eSsXS/X2cltEPDM+K9qZmIv+Ey1w0tg1+6caSe8TU5Hgw4oSTwNMf/6cQb3LzQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-html@0.0.68: + resolution: {integrity: sha512-fru9gsLJxy33xAltXOh4TEdi312HP80hpuKhpYQD4O5hDnkNPEBdcQkpB+gcX0oK0VxRv1UOzcGQEUzWCVHLfA==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-prettier@0.0.68: + resolution: {integrity: sha512-grUmWHkHlebMOd6V8vXs2eNQUw/bJGJMjekh/EPf/p2ZNTK0Uyz7hoBRngcvGfJHMsSXZH8w/dZTForIW/4ihw==} + peerDependencies: + '@volar/language-service': ~2.4.0 + prettier: ^2.2 || ^3.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + prettier: + optional: true + + volar-service-typescript-twoslash-queries@0.0.68: + resolution: {integrity: sha512-NugzXcM0iwuZFLCJg47vI93su5YhTIweQuLmZxvz5ZPTaman16JCvmDZexx2rd5T/75SNuvvZmrTOTNYUsfe5w==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-typescript@0.0.68: + resolution: {integrity: sha512-z7B/7CnJ0+TWWFp/gh2r5/QwMObHNDiQiv4C9pTBNI2Wxuwymd4bjEORzrJ/hJ5Yd5+OzeYK+nFCKevoGEEeKw==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-yaml@0.0.68: + resolution: {integrity: sha512-84XgE02LV0OvTcwfqhcSwVg4of3MLNUWPMArO6Aj8YXqyEVnPu8xTEMY2btKSq37mVAPuaEVASI4e3ptObmqcA==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + vscode-css-languageservice@6.3.10: + resolution: {integrity: sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==} + + vscode-html-languageservice@5.6.2: + resolution: {integrity: sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==} + + vscode-json-languageservice@4.1.8: + resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==} + engines: {npm: '>=7.0.0'} + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -2137,6 +2385,10 @@ packages: resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} engines: {node: '>=18'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} @@ -2144,6 +2396,19 @@ packages: xxhash-wasm@1.1.0: resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaml-language-server@1.19.2: + resolution: {integrity: sha512-9F3myNmJzUN/679jycdMxqtydPSDRAarSj3wPiF7pchEPnO9Dg07Oc+gIYLqXR4L+g+FSEVXXv2+mr54StLFOg==} + hasBin: true + + yaml@2.7.1: + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} + engines: {node: '>= 14'} + hasBin: true + yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -2153,6 +2418,10 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@1.2.2: resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} @@ -2184,10 +2453,46 @@ packages: snapshots: + '@astrojs/check@0.9.6(prettier@3.8.1)(typescript@5.9.3)': + dependencies: + '@astrojs/language-server': 2.16.3(prettier@3.8.1)(typescript@5.9.3) + chokidar: 4.0.3 + kleur: 4.1.5 + typescript: 5.9.3 + yargs: 17.7.2 + transitivePeerDependencies: + - prettier + - prettier-plugin-astro + '@astrojs/compiler@2.13.0': {} '@astrojs/internal-helpers@0.7.5': {} + '@astrojs/language-server@2.16.3(prettier@3.8.1)(typescript@5.9.3)': + dependencies: + '@astrojs/compiler': 2.13.0 + '@astrojs/yaml2ts': 0.2.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@volar/kit': 2.4.28(typescript@5.9.3) + '@volar/language-core': 2.4.28 + '@volar/language-server': 2.4.28 + '@volar/language-service': 2.4.28 + muggle-string: 0.4.1 + tinyglobby: 0.2.15 + volar-service-css: 0.0.68(@volar/language-service@2.4.28) + volar-service-emmet: 0.0.68(@volar/language-service@2.4.28) + volar-service-html: 0.0.68(@volar/language-service@2.4.28) + volar-service-prettier: 0.0.68(@volar/language-service@2.4.28)(prettier@3.8.1) + volar-service-typescript: 0.0.68(@volar/language-service@2.4.28) + volar-service-typescript-twoslash-queries: 0.0.68(@volar/language-service@2.4.28) + volar-service-yaml: 0.0.68(@volar/language-service@2.4.28) + vscode-html-languageservice: 5.6.2 + vscode-uri: 3.1.0 + optionalDependencies: + prettier: 3.8.1 + transitivePeerDependencies: + - typescript + '@astrojs/markdown-remark@6.3.10': dependencies: '@astrojs/internal-helpers': 0.7.5 @@ -2249,6 +2554,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@astrojs/yaml2ts@0.2.2': + dependencies: + yaml: 2.8.2 + '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} @@ -2268,6 +2577,29 @@ snapshots: '@ctrl/tinycolor@4.2.0': {} + '@emmetio/abbreviation@2.3.3': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-abbreviation@2.1.8': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-parser@0.4.1': + dependencies: + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 + + '@emmetio/html-matcher@1.3.0': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/scanner@1.0.4': {} + + '@emmetio/stream-reader-utils@0.1.0': {} + + '@emmetio/stream-reader@2.2.0': {} + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 @@ -2551,15 +2883,15 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true - '@jongio/azd-web-core@2.1.0(astro@5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))(tailwindcss@4.1.18)': - dependencies: - astro: 5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) - tailwindcss: 4.1.18 - - '@jongio/azd-web-core@2.4.0(astro@5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))(tailwindcss@4.1.18)': + '@jongio/azd-web-core@2.4.1(astro@5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2))(prettier@3.8.1)(tailwindcss@4.1.18)(typescript@5.9.3)': dependencies: + '@astrojs/check': 0.9.6(prettier@3.8.1)(typescript@5.9.3) astro: 5.17.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.55.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) tailwindcss: 4.1.18 + transitivePeerDependencies: + - prettier + - prettier-plugin-astro + - typescript '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -2836,12 +3168,73 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@volar/kit@2.4.28(typescript@5.9.3)': + dependencies: + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + typesafe-path: 0.2.2 + typescript: 5.9.3 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/language-server@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + path-browserify: 1.0.1 + request-light: 0.7.0 + vscode-languageserver: 9.0.1 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/language-service@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vscode/emmet-helper@2.11.0': + dependencies: + emmet: 2.4.11 + jsonc-parser: 2.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + '@vscode/l10n@0.0.18': {} + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 acorn@8.15.0: {} + ajv-draft-04@1.0.0(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-align@3.0.1: dependencies: string-width: 4.2.3 @@ -2850,6 +3243,10 @@ snapshots: ansi-regex@6.2.2: {} + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + ansi-styles@6.2.3: {} anymatch@3.1.3: @@ -3028,6 +3425,10 @@ snapshots: character-reference-invalid@2.0.1: {} + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chokidar@5.0.0: dependencies: readdirp: 5.0.0 @@ -3036,10 +3437,22 @@ snapshots: cli-boxes@3.0.0: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clsx@2.1.1: {} collapse-white-space@2.1.0: {} + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + comma-separated-tokens@2.0.3: {} commander@11.1.0: {} @@ -3136,6 +3549,11 @@ snapshots: electron-to-chromium@1.5.267: {} + emmet@2.4.11: + dependencies: + '@emmetio/abbreviation': 2.3.3 + '@emmetio/css-abbreviation': 2.1.8 + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} @@ -3273,6 +3691,10 @@ snapshots: extend@3.0.2: {} + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.0: {} + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -3295,6 +3717,8 @@ snapshots: fsevents@2.3.3: optional: true + get-caller-file@2.0.5: {} + get-east-asian-width@1.4.0: {} get-tsconfig@4.13.0: @@ -3514,8 +3938,16 @@ snapshots: dependencies: argparse: 2.0.1 + json-schema-traverse@1.0.0: {} + + jsonc-parser@2.3.1: {} + + jsonc-parser@3.3.1: {} + kleur@3.0.3: {} + kleur@4.1.5: {} + lightningcss-android-arm64@1.30.2: optional: true @@ -3565,6 +3997,8 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + lodash@4.17.21: {} + longest-streak@3.1.0: {} lru-cache@11.2.5: {} @@ -4024,6 +4458,8 @@ snapshots: ms@2.1.3: {} + muggle-string@0.4.1: {} + nanoid@3.3.11: {} neotraverse@0.6.18: {} @@ -4096,6 +4532,8 @@ snapshots: dependencies: entities: 6.0.1 + path-browserify@1.0.1: {} + piccolore@0.1.3: {} picocolors@1.1.1: {} @@ -4130,6 +4568,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prettier@3.8.1: {} + prismjs@1.30.0: {} prompts@2.4.2: @@ -4141,6 +4581,8 @@ snapshots: radix3@1.1.2: {} + readdirp@4.1.2: {} + readdirp@5.0.0: {} recma-build-jsx@1.0.0: @@ -4267,6 +4709,14 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 + request-light@0.5.8: {} + + request-light@0.7.0: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + resolve-pkg-maps@1.0.0: {} retext-latin@4.0.0: @@ -4458,6 +4908,12 @@ snapshots: type-fest@4.41.0: {} + typesafe-path@0.2.2: {} + + typescript-auto-import-cache@0.3.6: + dependencies: + semver: 7.7.3 + typescript@5.9.3: {} ufo@1.6.2: {} @@ -4586,6 +5042,103 @@ snapshots: optionalDependencies: vite: 6.4.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) + volar-service-css@0.0.68(@volar/language-service@2.4.28): + dependencies: + vscode-css-languageservice: 6.3.10 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-emmet@0.0.68(@volar/language-service@2.4.28): + dependencies: + '@emmetio/css-parser': 0.4.1 + '@emmetio/html-matcher': 1.3.0 + '@vscode/emmet-helper': 2.11.0 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-html@0.0.68(@volar/language-service@2.4.28): + dependencies: + vscode-html-languageservice: 5.6.2 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-prettier@0.0.68(@volar/language-service@2.4.28)(prettier@3.8.1): + dependencies: + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + prettier: 3.8.1 + + volar-service-typescript-twoslash-queries@0.0.68(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-typescript@0.0.68(@volar/language-service@2.4.28): + dependencies: + path-browserify: 1.0.1 + semver: 7.7.3 + typescript-auto-import-cache: 0.3.6 + vscode-languageserver-textdocument: 1.0.12 + vscode-nls: 5.2.0 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-yaml@0.0.68(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.1.0 + yaml-language-server: 1.19.2 + optionalDependencies: + '@volar/language-service': 2.4.28 + + vscode-css-languageservice@6.3.10: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + vscode-html-languageservice@5.6.2: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + vscode-json-languageservice@4.1.8: + dependencies: + jsonc-parser: 3.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-nls: 5.2.0 + vscode-uri: 3.1.0 + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-nls@5.2.0: {} + + vscode-uri@3.1.0: {} + web-namespaces@2.0.1: {} which-pm-runs@1.1.0: {} @@ -4594,6 +5147,12 @@ snapshots: dependencies: string-width: 7.2.0 + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 @@ -4602,11 +5161,39 @@ snapshots: xxhash-wasm@1.1.0: {} - yaml@2.8.2: - optional: true + y18n@5.0.8: {} + + yaml-language-server@1.19.2: + dependencies: + '@vscode/l10n': 0.0.18 + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + lodash: 4.17.21 + prettier: 3.8.1 + request-light: 0.5.8 + vscode-json-languageservice: 4.1.8 + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + yaml: 2.7.1 + + yaml@2.7.1: {} + + yaml@2.8.2: {} yargs-parser@21.1.1: {} + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@1.2.2: {} yocto-spinner@0.2.3: diff --git a/web/package.json b/web/package.json index 2e78401..a6e4c92 100644 --- a/web/package.json +++ b/web/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@astrojs/mdx": "^4.3.13", - "@jongio/azd-web-core": "^2.4.0", + "@jongio/azd-web-core": "^2.4.1", "astro": "^5.17.1", "astro-expressive-code": "^0.41.6" },