Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cli/azd/.vscode/cspell-azd-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Errorf
Frontends
GOARCH
GOCOVERDIR
GOTOOLCHAIN
GOWORK
Ghostty
LASTEXITCODE
MCPJSON
Expand Down Expand Up @@ -110,6 +112,7 @@ containerapps
containerd
containerizable
contoso
covdata
createdby
csharpapp
csharpapptest
Expand Down Expand Up @@ -153,6 +156,7 @@ go-imath
godotenv
gofmt
golangci
googleapis
gosec
goterm
gotest
Expand Down Expand Up @@ -199,6 +203,7 @@ mysqladmin
mysqlclient
mysqldb
nazd
ndjson
nobanner
nodeapp
nolint
Expand Down
8 changes: 4 additions & 4 deletions cli/azd/.vscode/cspell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ overrides:
- filename: cmd/mcp.go
words:
- internalcmd
- filename: cmd/extension.go
words:
- compatResult
- compatCopy
- filename: pkg/azdext/config_helper.go
words:
- myext
Expand Down Expand Up @@ -364,10 +368,6 @@ overrides:
- filename: pkg/infra/provisioning/bicep/local_preflight.go
words:
- actioned
- filename: docs/code-coverage-guide.md
words:
- covdata
- GOWORK
ignorePaths:
- "**/*_test.go"
- "**/mock*.go"
Expand Down
1 change: 1 addition & 0 deletions cli/azd/internal/appdetect/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func PyFastApiLaunch(projectPath string) (string, error) {
}

if strings.HasSuffix(path, "main.py") || strings.HasSuffix(path, "app.py") {
//nolint:gosec // G122: local project contents are trusted for FastAPI detection.
f, err := os.Open(path)
if err != nil {
return err
Expand Down
14 changes: 13 additions & 1 deletion cli/azd/internal/repository/initializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,23 @@ func (i *Initializer) copyLocalTemplate(source, destination string) error {
}
var matchers []gitignoreMatcher

sourceRoot, err := os.OpenRoot(source)
if err != nil {
return fmt.Errorf("opening local template root: %w", err)
}
defer sourceRoot.Close()

_ = filepath.WalkDir(source, func(path string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() || d.Name() != ".gitignore" {
return err
}
data, readErr := os.ReadFile(path)

rel, relErr := filepath.Rel(source, path)
if relErr != nil {
return relErr
}

data, readErr := sourceRoot.ReadFile(rel)
if readErr != nil {
return nil // skip unreadable gitignore files
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import (
func getParentProcessInfoWithPPID(pid int) (parentProcessInfo, int, error) {
info := parentProcessInfo{}
parentPid := 0
pidArg := strconv.Itoa(pid)

// Use ps to get process info and parent PID
// -o comm= gives just the command name, -o ppid= gives parent PID
cmd := exec.Command("ps", "-p", fmt.Sprintf("%d", pid), "-o", "comm=,ppid=")
//nolint:gosec // G204: pidArg is derived from an integer process ID, not shell input.
cmd := exec.Command("ps", "-p", pidArg, "-o", "comm=,ppid=")
output, err := cmd.Output()
if err != nil {
return info, 0, fmt.Errorf("failed to get process info: %w", err)
Expand All @@ -37,7 +39,8 @@ func getParentProcessInfoWithPPID(pid int) (parentProcessInfo, int, error) {
}

// Get the full command path
cmd = exec.Command("ps", "-p", fmt.Sprintf("%d", pid), "-o", "args=")
//nolint:gosec // G204: pidArg is derived from an integer process ID, not shell input.
cmd = exec.Command("ps", "-p", pidArg, "-o", "args=")
output, err = cmd.Output()
if err == nil {
cmdLine := strings.TrimSpace(string(output))
Expand All @@ -52,7 +55,8 @@ func getParentProcessInfoWithPPID(pid int) (parentProcessInfo, int, error) {

// If we couldn't get the executable from args, try lsof
if info.Executable == "" {
cmd = exec.Command("lsof", "-p", fmt.Sprintf("%d", pid), "-Fn")
//nolint:gosec // G204: pidArg is derived from an integer process ID, not shell input.
cmd = exec.Command("lsof", "-p", pidArg, "-Fn")
output, err = cmd.Output()
if err == nil {
// Parse lsof output - lines starting with 'n' contain file names
Expand Down
9 changes: 5 additions & 4 deletions cli/azd/internal/vsrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ func (s *Server) Serve(l net.Listener) error {
}

// Run upload periodically in the background while the server is running.
ctx, cancel := context.WithCancel(context.Background()) //nolint:gosec // G118: cancel stored in s.cancelTelemetryUpload
//nolint:gosec // G118: cancel is stored on the server and invoked later by StopAsync.
ctx, cancel := context.WithCancel(context.Background())
ts := telemetry.GetTelemetrySystem()
backgroundTelemetry := func() {
ticker := time.NewTicker(5 * time.Second)
Expand Down Expand Up @@ -213,9 +214,9 @@ func serveRpc(w http.ResponseWriter, r *http.Request, handlers map[string]Handle
call, isCall := req.(*jsonrpc2.Call)
if isCall {
span.SetAttributes(fields.JsonRpcId.String(fmt.Sprint(call.ID())))
//nolint:gosec // G118: cancel stored in cancelers map and called on completion
ctx, cancel := context.WithCancel(ctx)
childCtx = ctx
var cancel context.CancelFunc
//nolint:gosec // G118: cancel is stored in cancelers and invoked later by request cancellation handling.
childCtx, cancel = context.WithCancel(childCtx)
cancelersMu.Lock()
cancelers[call.ID()] = cancel
cancelersMu.Unlock()
Expand Down
2 changes: 1 addition & 1 deletion cli/azd/pkg/azdext/atomicfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
// WriteFileAtomic writes data to the named file atomically. It writes to a
// temporary file in the same directory as path and renames it into place. This
// ensures that readers never see a partially-written file and that the
// operation is crash-safe on filesystems that support atomic rename (ext4,
// operation is crash-safe on file systems that support atomic rename (ext4,
// APFS, NTFS).
//
// Platform behavior:
Expand Down
2 changes: 1 addition & 1 deletion cli/azd/pkg/azdext/azd_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func WithAddress(address string) AzdClientOption {
if isLocalhostAddress(address) {
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
} else {
// For non-localhost connections, require TLS to prevent MITM attacks
// For non-localhost connections, require TLS to prevent man-in-the-middle attacks.
opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(nil)))
}

Expand Down
7 changes: 5 additions & 2 deletions cli/azd/pkg/azdext/process_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ func isProcessRunningOS(pid int) bool {
// getProcessInfoOS retrieves process info on macOS using ps(1).
func getProcessInfoOS(pid int) ProcessInfo {
info := ProcessInfo{PID: pid}
pidArg := strconv.Itoa(pid)

// Use ps to get process name and executable path.
cmd := exec.Command("ps", "-p", strconv.Itoa(pid), "-o", "comm=")
//nolint:gosec // G204: pidArg is derived from an integer process ID, not shell input.
cmd := exec.Command("ps", "-p", pidArg, "-o", "comm=")
output, err := cmd.Output()
if err != nil {
return info // Process does not exist or is inaccessible.
Expand All @@ -39,7 +41,8 @@ func getProcessInfoOS(pid int) ProcessInfo {
info.Running = true

// Get full command path.
cmd = exec.Command("ps", "-p", strconv.Itoa(pid), "-o", "args=")
//nolint:gosec // G204: pidArg is derived from an integer process ID, not shell input.
cmd = exec.Command("ps", "-p", pidArg, "-o", "args=")
output, err = cmd.Output()
if err == nil {
args := strings.TrimSpace(string(output))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ func (t *TerraformProvider) createInputParametersFile(
}

log.Printf("Writing parameters file to: %s", inputFilePath)
//nolint:gosec // G703: path derived from infra config, not user input
//nolint:gosec // G703: inputFilePath is derived from azd's managed .azure environment directory.
err = os.WriteFile(inputFilePath, []byte(replaced), 0600)
if err != nil {
return fmt.Errorf("writing parameter file: %w", err)
Expand Down
3 changes: 2 additions & 1 deletion cli/azd/pkg/tools/dotnet/dotnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ func (cli *Cli) PublishAppHostManifest(
)
}

return os.WriteFile(manifestPath, m, osutil.PermissionFile) //nolint:gosec // G703: path from known project structure
//nolint:gosec // G703: manifestPath is the azd-managed output path for the generated manifest.
return os.WriteFile(manifestPath, m, osutil.PermissionFile)
}

// For single-file apphost, we need to use the .cs file directly
Expand Down
9 changes: 5 additions & 4 deletions cli/azd/pkg/ux/spinner.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,18 @@ func (s *Spinner) Start(ctx context.Context) error {
s.canvas = NewCanvas(s).WithWriter(s.options.Writer)
}

// Use a context to determine when to stop the spinner
cancelCtx, cancel := context.WithCancel(ctx) //nolint:gosec // G118: cancel stored in s.cancel and called in Stop()
s.cancel = cancel

s.clear = false
s.cursor.HideCursor()

if err := s.canvas.Run(); err != nil {
return err
}

// Use a context to determine when to stop the spinner updates.
//nolint:gosec // G118: s.cancel is stored and invoked later by Stop.
cancelCtx, cancel := context.WithCancel(ctx)
s.cancel = cancel

// Periodic update goroutine
go func(ctx context.Context) {
for {
Expand Down
Loading