# UNDF: UNDF-2026-000000510
# pulumi-0001: package_info.go Required slice O(P×R) membership test

## Classification
- **Severity**: MEDIUM
- **CWE**: CWE-407 (Algorithmic Complexity — Inefficient Algorithmic Complexity)
- **Component**: `pkg/cmd/pulumi/packagecmd/package_info.go`

## Location
`pkg/cmd/pulumi/packagecmd/package_info.go` — four identical patterns:

**Pattern 1** (line 330–336): Function input properties display
```go
for _, name := range maputil.SortedKeys(fun.Inputs.Properties) {
    if slices.Contains(fun.Inputs.Required, name) {  // O(R) per property
        ...
    }
}
```

**Pattern 2** (line 364–370): Function output properties display
```go
for _, name := range maputil.SortedKeys(obj.Properties) {
    if slices.Contains(obj.Required, name) {  // O(R) per property
        ...
    }
}
```

**Pattern 3** (line 448–454): Resource input properties display
```go
for _, name := range maputil.SortedKeys(res.InputProperties) {
    if slices.Contains(res.RequiredInputs, name) {  // O(R) per property
        ...
    }
}
```

**Pattern 4** (line 471–476): Resource output properties display
```go
for _, name := range maputil.SortedKeys(res.Properties) {
    if slices.Contains(res.Required, name) {  // O(R) per property
        ...
    }
}
```

## Pattern
`Required`/`RequiredInputs` are `[]string` slices. `slices.Contains` performs a full O(R) linear scan for each of P properties in the outer loop → O(P × R) total per resource/function display.

For a provider with P=500 properties and R=200 required fields (common in large providers like AWS, Azure, GCP), each `pulumi package get-resource` or `pulumi package get-function` call performs 100,000 string comparisons.

## Speedup
At P=500, R=200: 100,000 comparisons → 700 comparisons (143x reduction)

## Patch

```diff
--- a/pkg/cmd/pulumi/packagecmd/package_info.go
+++ b/pkg/cmd/pulumi/packagecmd/package_info.go
@@ -326,9 +326,14 @@ func printFunctionDetails(...) error {
+	requiredSet := make(map[string]bool, len(fun.Inputs.Required))
+	for _, r := range fun.Inputs.Required {
+		requiredSet[r] = true
+	}
 	for _, name := range maputil.SortedKeys(fun.Inputs.Properties) {
-		if slices.Contains(fun.Inputs.Required, name) {
+		if requiredSet[name] {
 			...
 		}
 	}
 	// similar changes for obj.Required, res.RequiredInputs, res.Required
```

## Complexity
- Before: O(P × R) per resource/function — P = properties, R = required fields
- After: O(P + R) — one pass to build set, one pass to display
