Skip to content

Commit 84f0136

Browse files
committed
fix: has() on non-container types returns error instead of false
has() applied to a non-container, non-optional value (e.g., an integer or string) previously returned false silently when errorOnBadPresenceTest was not enabled. This caused !has(x.field) to evaluate to true when x was an unexpected type, creating a fail-open condition in policy expressions that use presence guards on dynamic inputs. This change narrows the default case in refQualify so that: - has() on a non-container, non-optional type (presenceOnly=true): returns missingKey error, preventing silent false returns - has() on an optional value (e.g. optional.none()): continues to return false, preserving correct optional semantics - Optional field selection (x.?field, presenceOnly=false): continues to return not-present for optional.none() compatibility - EnableErrorOnBadPresenceTest(true): errors for all cases (unchanged) No test expectations changed. Full suite green. Signed-off-by: Koda Reef <koda.reef5@gmail.com>
1 parent d942970 commit 84f0136

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

interpreter/attributes.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1419,7 +1419,14 @@ func refQualify(adapter types.Adapter, obj any, idx ref.Val, presenceTest, prese
14191419
return val, true, nil
14201420
default:
14211421
if presenceTest && !errorOnBadPresenceTest {
1422-
return nil, false, nil
1422+
if _, isOpt := celVal.(*types.Optional); isOpt || !presenceOnly {
1423+
// Optional values and optional field selection correctly
1424+
// report not-present for non-container types.
1425+
return nil, false, nil
1426+
}
1427+
// has() macro on a non-container, non-optional type (e.g.
1428+
// has(int_value.field)) errors to prevent silent fail-open
1429+
// in policy expressions using presence guards on dynamic inputs.
14231430
}
14241431
return nil, false, missingKey(idx)
14251432
}

0 commit comments

Comments
 (0)