Skip to content

feat: apl-addons ArgoCD project for platform-admin addon deployments #3428

Description

@j-zimnowoda

Problem Statement

Platform admins have no supported way to deploy arbitrary Kubernetes addons — cross-namespace operators, CRDs, Helm charts spanning multiple namespaces — without going through the team-scoped AppProject model. Every existing AppProject is locked to a single team namespace and forbids cluster-scoped resources. There is no escape hatch for platform-level addon management.

Solution

Introduce an apl-addons ArgoCD AppProject and namespace. Platform admins drop ArgoCD Application CRs into env/manifests/namespaces/apl-addons/ in the values repo. The existing addGitOpsApps mechanism automatically creates a gitops-ns-apl-addons ArgoCD Application (App-of-Apps) that syncs those Application CRs into the apl-addons namespace. ArgoCD's "app in any namespace" feature then reconciles them under the fully-unrestricted apl-addons project.

User Stories

  1. As a platform admin, I want to drop an ArgoCD Application CR into env/manifests/namespaces/apl-addons/ and have it automatically reconciled by ArgoCD, so that I can deploy addons without manual cluster access.
  2. As a platform admin, I want the env/manifests/namespaces/apl-addons/ directory to exist immediately after APL installs or upgrades, so that I do not need to create it manually before I can use the feature.
  3. As a platform admin, I want Applications in the apl-addons project to be able to deploy to any namespace on any registered cluster, so that I can install cross-namespace and cluster-scoped addons without restriction.
  4. As a platform admin, I want Applications in the apl-addons project to be able to pull from any git repository or Helm registry, so that I am not limited to pre-approved sources when choosing addons.
  5. As a platform admin, I want Applications in the apl-addons project to be able to deploy any Kubernetes resource type including cluster-scoped resources, so that I can manage CRDs, ClusterRoles, and StorageClasses as addons.
  6. As a platform admin, I want the apl-addons AppProject to be protected from accidental deletion at the API-server level, so that the project cannot be removed even by someone stripping ArgoCD finalizers.
  7. As a platform admin, I want the apl-addons namespace to be created automatically when the first Application CR is synced there, so that I do not need to pre-create it.
  8. As a platform admin, I want the apl-addons AppProject to be visible and manageable in the ArgoCD UI using my existing platform-admin credentials, so that I do not need separate RBAC configuration.
  9. As a platform admin, I want Applications I place in apl-addons to be pruned from the cluster when I remove their manifests from git, so that deleting a file is sufficient to remove the addon.
  10. As a platform admin, I want to understand that Application CRs in env/manifests/namespaces/apl-addons/ must set spec.project: apl-addons, so that I know why ArgoCD will reject them if this field is wrong.
  11. As a platform admin, I want to understand that the argocd namespace must not be used as a destination, so that I do not accidentally overwrite ArgoCD's own configuration.
  12. As a security-conscious operator, I want images deployed into the apl-addons namespace to still be subject to the ORCS registry Kyverno policy, so that the addon escape hatch does not bypass image provenance enforcement.

Implementation Decisions

Bootstrap: env/manifests/namespaces/apl-addons/

ensureManifestDirectories in src/common/utils.ts must be extended to also call ensureDirectoryWithGitkeepAsync for env/manifests/namespaces/apl-addons/. This ensures the directory exists after every APL install or upgrade, which in turn causes addGitOpsApps to automatically create the gitops-ns-apl-addons Application on the next reconciliation cycle.

No changes are needed to addGitOpsApps, calculateGitOpsAppsSyncState, or getArgocdGitopsManifest — the existing namespace-directory scanning logic handles apl-addons as just another namespace directory.

ArgoCD "app in any namespace" wiring

In values/argocd/argocd.gotmpl, add apl-addons to two config sections:

  • configs.cm: application.namespaces: apl-addons — enables ArgoCD to watch Application CRs in the apl-addons namespace (writes to argocd-cm)
  • configs.params: application.namespaces: apl-addons — enables the conditional extra verbs on the ArgoCD server ClusterRole in charts/argocd/templates/argocd-server/clusterrole.yaml (lines 52–62 are already gated on this value)

AppProject apl-addons

Add an AppProject resource to values/argocd/argocd-raw.gotmpl. Spec:

  • sourceRepos: ['*']
  • sourceNamespaces: ['apl-addons']
  • destinations: [{namespace: '*', server: '*'}]
  • clusterResourceWhitelist: [{group: '*', kind: '*'}]
  • namespaceResourceBlacklist: []
  • No ArgoCD finalizer (protected by VAP instead — see below)

The project carries no roles. The platform-admin OIDC group already maps to role:admin globally in argocd.gotmpl policy.csv and therefore has full access.

ValidatingAdmissionPolicy

Add a ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding to values/argocd/argocd-raw.gotmpl that denies DELETE operations on the AppProject named apl-addons in the argocd namespace. This protects the project at the API-server level, which cannot be bypassed by stripping ArgoCD finalizers.

Naming convention deviation

The existing ADR 2026-06-25-manifests-directory.md states that apl--prefixed namespace directories are operator-owned. apl-addons is a deliberate exception: the operator bootstraps it but platform admins own its contents. This deviation and its rationale are recorded in adr/2026-07-07-apl-addons-argocd-project.md.

Unenforced constraints (document only)

  • Application CRs must set spec.project: apl-addons. ArgoCD enforces this with an RBAC error; no operator-level pre-validation is added.
  • The argocd namespace must not be used as a destination. ArgoCD AppProject has no native destination blacklist; this is documented rather than enforced.

Testing Decisions

Good tests assert observable outcomes (directory exists, manifest shape, required app set) without coupling to internal call order or mock counts.

Seam 1: ensureManifestDirectoriessrc/common/utils.test.ts

Add a test that calls ensureManifestDirectories and asserts that ensureDirectoryWithGitkeepAsync is invoked for env/manifests/namespaces/apl-addons/. Prior art: the ensureTeamGitOpsDirectories tests in the same file use the same dependency-injection pattern.

Seam 2: calculateGitOpsAppsSyncStatesrc/cmd/apply-as-apps.test.ts

Add a test case where the mocked glob returns apl-addons as one of the namespace directories and asserts that gitops-ns-apl-addons appears in requiredGitOpsApps. No code changes required; this is a documentation test that makes the intent explicit. Prior art: the existing calculateGitOpsAppsSyncState describe block in the same file.

Helm template rendering (argocd-raw.gotmpl, argocd.gotmpl) is not unit-tested in this repo and is validated by deployment.

Out of Scope

  • Restricting which destination namespaces the apl-addons project can target (ArgoCD has no native destination blacklist; this would require a Kyverno admission policy)
  • Operator-level validation that Application CRs reference project: apl-addons
  • Excluding the apl-addons namespace from the ORCS registry Kyverno policy
  • Multi-namespace or wildcard application.namespaces configuration
  • Any UI or API surface for platform admins to manage addons outside of git

Further Notes

  • The gitops-ns-apl-addons Application is created automatically by the existing addGitOpsApps reconciliation loop — no new operator code path is introduced for it.
  • The parent gitops-ns-apl-addons Application runs under project: default (the existing behaviour for all gitops-ns-* applications) and syncs Application CRs into the apl-addons namespace. The default project is fully permissive and allows this.
  • See adr/2026-07-07-apl-addons-argocd-project.md for the full record of design decisions and trade-offs.
  • See CONTEXT.md for the canonical glossary of terms used above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified, ready for an AFK agent

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions