You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
AppProject destination deny (!name / !server) is ignored when the same entry's other identifier matches the cluster #30588
I've pasted the output of argocd version below (adapted: master, unreleased, commit db81aa3 — see Version).
Describe the bug
The project documentation states a destination is valid only if an allow rule permits it AND no deny rule (prefixed with !) rejects it. In AppProject.isDestinationMatched (pkg/apis/application/v1alpha1/app_project_types.go), a deny pattern that positively matches a cluster is ignored whenever the SAME destination entry's other identifier matches the cluster, because the allow case is evaluated first: matched := (dstServerMatched || dstNameMatched) && dstNamespaceMatched. The deny case only fires when neither identifier matched, i.e. exactly when the deny did not positively match anything.
Verified on master (db81aa3) with a unit-level check against the real package:
Project destination {name: "!bad-cluster", server: "https://api.example.com", namespace: "*"} and cluster (name "bad-cluster", server "https://api.example.com") → IsDestinationPermitted returns true. Expected: false — the name deny matches this cluster and must reject it.
Mirror image: destination {name: "good-cluster", server: "!https://api.example.com", namespace: "*"} and cluster (name "good-cluster", server "https://api.example.com") → returns true. Expected: false.
Controls behave correctly: a plain allow entry permits, and a name-only deny entry ({name: "!bad-cluster", namespace: "*"}) does reject the cluster.
This is distinct from #21264: that issue is about a deny entry passively "granting" access to clusters it does not match (negative matching semantics). Here the deny pattern DOES match the cluster and still fails to reject it, because it is combined with an allow pattern for the other identifier in the same entry. Namespace denies do have a dedicated enforcing case in the same function; name/server denies do not.
To Reproduce
Configure an AppProject with the first destination above and attempt to deploy an Application to cluster "bad-cluster" (https://api.example.com) in any namespace — it is permitted despite the explicit !bad-cluster deny. No cluster is needed to reproduce the core behaviour; it is visible in IsDestinationPermitted/isDestinationMatched directly.
Expected behavior
A deny pattern that positively matches the cluster's name or server vetoes the destination entry (for a matching namespace), regardless of whether the entry's other identifier matches.
Screenshots
Not applicable.
Version
master (unreleased), commit db81aa3; pure Go logic in pkg/apis/application/v1alpha1, reproduces without a cluster.
Logs
Not applicable — pure Go logic, reproduces without a cluster.
Activity