Skip to content

AppProject destination deny (!name / !server) is ignored when the same entry's other identifier matches the cluster #30588

Open

Description

@Sun-Wukhan

Checklist:

  • I've searched in the docs and FAQ for my answer: https://bit.ly/argocd-faq.
  • I've included steps to reproduce the bug.
  • 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

  1. added
    bugSomething isn't working
    triage/pendingThis issue needs further triage to be correctly classified
    on Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriage/pendingThis issue needs further triage to be correctly classified

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions