Files
deploy/manifests/crds/appproject-crd.yaml
41536738c8 refactor(cd): hard-fork - rename CRD API group argoproj.io -> deploy.hanzo.ai (#1)
* feat(api): hard-fork CRD API group argoproj.io -> deploy.hanzo.ai

Hanzo CD hard-fork, phase 1.1. Single source of truth is
pkg/apis/application/register.go's Group constant (Application/AppProject/
ApplicationSet all derive their FullName from it); every other Go call-site
that hardcoded the literal group string is updated to match: the 3 generated
informer GVRs, the app-of-apps nested-Application detector in types.go, the
resource-tree Application-kind cache populator, the 3 NotFound error
constructors in server/application, and the applicationset-controller's
leader-election Lease name/ID (kept in lockstep across Go source + RBAC
resourceNames, or leader election would get RBAC-denied on startup).

CRD YAMLs (application/appproject/applicationset) and every RBAC apiGroups
rule that actually governs our 3 CRDs are repointed to deploy.hanzo.ai, across
both manifests/base/* (namespaced Roles) and manifests/cluster-rbac/* (cluster
scope). Two adjacent things that share the "argoproj.io" string but are NOT
ours are deliberately left untouched: gitops-engine's health-check dispatch
for Argo Workflows' `Workflow` kind, and argocd-server-clusterrole's second
apiGroups block granting read on Argo Workflows' `workflows` resource — both
belong to a separate, unrelated Argoproj-family project we are not forking.

Also untouched, per explicit scope: annotation/label keys (argocd.argoproj.io/*)
and finalizers (*.argoproj.io) that track already-applied live resources, and
argocd-cm.yaml's resource.customizations.ignoreResourceUpdates keys (a narrow
app-of-apps diffing nicety, not build- or RBAC-relevant).

CGO_ENABLED=0 go build ./... verified green.

* ci: wire canonical hanzo.yml + cicd.yml (Hanzo CD image build)

Phase 1.3. Follows the same one-way pattern every hanzo/lux/zoo repo uses:
hanzo.yml declares the image (root Dockerfile -> ghcr.io/hanzoai/deploy) and a
fast go-build sanity test (the multi-stage Dockerfile build is the slow, real
gate); cicd.yml is the ~10-line trigger shim importing hanzoai/ci's reusable
build workflow on the arc pool, secrets from KMS only.

No `deploy:` block yet, matching the hanzoai/cms build-only-first-cutover
pattern: this repo's own live hanzo-cd namespace runs the whole Hanzo fleet's
GitOps, so the prod image/CRD swap is a deliberate separate action (see the
[HELD] universe PR), never an automatic rollout on merge. Every PR/push still
builds and pushes an immutable ghcr.io/hanzoai/deploy:sha-<7>-amd64 image.

* feat(ui): rebrand Argo CD -> Hanzo CD (title, favicon, logo, sidebar)

Phase 1.2. User-facing "Argo CD"/"ArgoCD" text replaced with "Hanzo CD"
across the login page, help modal, settings screens, version-info panel,
sync-options warning, fullscreen-logs title, app.tsx page titles, and
index.html's <title>/noscript text (dropped the now-wrong upstream CLI
doc link rather than invent a hanzo.ai URL that doesn't exist).

Logo/favicon assets replaced with the canonical Hanzo mark (never
hand-drawn, copied from ~/work/hanzo/logo/dist): the two real usages of
Argo's logo collapse onto one Hanzo glyph (mono + white variants) at the
same 5 call sites (login icon + footer, login.scss $logoPath/
$logoNegativePath, sidebar text-logo), preserving the existing CSS
invert() filters so both the light login panel and dark sidebar still
render correctly. Old argologo.svg/argo_o.svg/argo.png deleted (no
longer referenced). favicon-{16x16,32x32}.png added at
ui/src/assets/favicon/ (index.html's links to that path were previously
dead - the directory didn't exist in this checkout). package.json name
argo-cd-ui -> hanzo-cd-ui.

Left alone, deliberately: the two Kubernetes resource-kind icon sets
under ui/src/assets/images/resources/ (unrelated to branding), and
upstream doc/project links (argoproj.io, argo-cd.readthedocs.io) since
we have no equivalent hanzo.ai docs to point to yet - except the login
footer logo's outbound link, which now points to hanzo.ai instead of
argoproj.io (a Hanzo-branded mark linking to the upstream project it
was forked from read as an obvious leftover).

* feat(module): rename Go module github.com/argoproj/argo-cd/v3 -> github.com/hanzoai/deploy

Phase 2. No version suffix on the new path (org policy: never publish our
own Go modules above v1.x.x / with a v2+ suffix) — this fork starts a fresh
v0/v1 module identity rather than carrying the v3 the upstream fork point
had reached.

Mechanical, symmetric rewrite: 704 .go files (import statements only; two
disjoint substitutions applied specific-first so the nested gitops-engine
module path never double-matches), plus go.mod (module line, the
gitops-engine require+replace pair, version reset to v0.0.0-... since a
suffix-less path can't carry a v3 semver), gitops-engine/go.mod, Makefile
(ldflags PACKAGE + 2 TEST_MODULE filters), .golangci.yaml, .goreleaser.yaml,
.mockery.yaml (+ gitops-engine's), Procfile, the codegen/proto generation
scripts (hack/generate-proto.sh, update-codegen.sh, update-openapi.sh), and
20 .proto files' go_package options. Also one OpenTelemetry tracer name
string in gitops-engine/pkg/sync/sync_context.go (a cosmestic label, not an
import, but worth keeping consistent).

CGO_ENABLED=0 go build ./... verified green for both the root module and
the nested gitops-engine module; go vet clean on both; go mod tidy run
(network available) to reconcile go.sum, dependency set unchanged.

Left alone, deliberately: doc-only mentions (docs/snyk/*.html scan reports,
gitops-engine/README.md), a comment-only reference in
.github/workflows/release.yaml, and one Renovate bot config line — none are
build- or codegen-load-bearing. Also left alone: comments citing upstream
GitHub issue URLs (github.com/argoproj/argo-cd/issues/NNNNN) and a handful
of test fixtures using "https://github.com/argoproj/argo-cd.git" as a
representative example repo URL — both are accurate historical/test-data
references, not stale self-references.

---------

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-29 18:27:58 -07:00

434 lines
19 KiB
YAML
Generated

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
labels:
app.kubernetes.io/name: appprojects.deploy.hanzo.ai
app.kubernetes.io/part-of: argocd
name: appprojects.deploy.hanzo.ai
spec:
group: deploy.hanzo.ai
names:
kind: AppProject
listKind: AppProjectList
plural: appprojects
shortNames:
- appproj
- appprojs
singular: appproject
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: |-
AppProject provides a logical grouping of applications, providing controls for:
* where the apps may deploy to (cluster whitelist)
* what may be deployed (repository whitelist, resource whitelist/blacklist)
* who can access these applications (roles, OIDC group claims bindings)
* and what they can do (RBAC policies)
* automation access to these roles (JWT tokens)
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: AppProjectSpec is the specification of an AppProject
properties:
clusterResourceBlacklist:
description: ClusterResourceBlacklist contains list of blacklisted
cluster level resources
items:
description: ClusterResourceRestrictionItem is a cluster resource
that is restricted by the project's whitelist or blacklist
properties:
group:
type: string
kind:
type: string
name:
description: |-
Name is the name of the restricted resource. Glob patterns using Go's filepath.Match syntax are supported.
Unlike the group and kind fields, if no name is specified, all resources of the specified group/kind are matched.
type: string
required:
- group
- kind
type: object
type: array
clusterResourceWhitelist:
description: ClusterResourceWhitelist contains list of whitelisted
cluster level resources
items:
description: ClusterResourceRestrictionItem is a cluster resource
that is restricted by the project's whitelist or blacklist
properties:
group:
type: string
kind:
type: string
name:
description: |-
Name is the name of the restricted resource. Glob patterns using Go's filepath.Match syntax are supported.
Unlike the group and kind fields, if no name is specified, all resources of the specified group/kind are matched.
type: string
required:
- group
- kind
type: object
type: array
description:
description: Description contains optional project description
maxLength: 255
type: string
destinationServiceAccounts:
description: DestinationServiceAccounts holds information about the
service accounts to be impersonated for the application sync operation
for each destination.
items:
description: ApplicationDestinationServiceAccount holds information
about the service account to be impersonated for the application
sync operation.
properties:
defaultServiceAccount:
description: DefaultServiceAccount to be used for impersonation
during the sync operation
type: string
namespace:
description: Namespace specifies the target namespace for the
application's resources.
type: string
server:
description: Server specifies the URL of the target cluster's
Kubernetes control plane API.
type: string
required:
- defaultServiceAccount
- server
type: object
type: array
destinations:
description: Destinations contains list of destinations available
for deployment
items:
description: ApplicationDestination holds information about the
application's destination
properties:
name:
description: Name is an alternate way of specifying the target
cluster by its symbolic name. This must be set if Server is
not set.
type: string
namespace:
description: |-
Namespace specifies the target namespace for the application's resources.
The namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace
type: string
server:
description: Server specifies the URL of the target cluster's
Kubernetes control plane API. This must be set if Name is
not set.
type: string
type: object
type: array
namespaceResourceBlacklist:
description: NamespaceResourceBlacklist contains list of blacklisted
namespace level resources
items:
description: |-
GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying
concepts during lookup stages without having partially valid types
properties:
group:
type: string
kind:
type: string
required:
- group
- kind
type: object
type: array
namespaceResourceWhitelist:
description: NamespaceResourceWhitelist contains list of whitelisted
namespace level resources
items:
description: |-
GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying
concepts during lookup stages without having partially valid types
properties:
group:
type: string
kind:
type: string
required:
- group
- kind
type: object
type: array
orphanedResources:
description: OrphanedResources specifies if controller should monitor
orphaned resources of apps in this project
properties:
ignore:
description: Ignore contains a list of resources that are to be
excluded from orphaned resources monitoring
items:
description: OrphanedResourceKey is a reference to a resource
to be ignored from
properties:
group:
type: string
kind:
type: string
name:
type: string
type: object
type: array
warn:
description: Warn indicates if warning condition should be created
for apps which have orphaned resources
type: boolean
type: object
permitOnlyProjectScopedClusters:
description: PermitOnlyProjectScopedClusters determines whether destinations
can only reference clusters which are project-scoped
type: boolean
roles:
description: Roles are user defined RBAC roles associated with this
project
items:
description: ProjectRole represents a role that has access to a
project
properties:
description:
description: Description is a description of the role
type: string
groups:
description: Groups are a list of OIDC group claims bound to
this role
items:
type: string
type: array
jwtTokens:
description: JWTTokens are a list of generated JWT tokens bound
to this role
items:
description: JWTToken holds the issuedAt and expiresAt values
of a token
properties:
exp:
format: int64
type: integer
iat:
format: int64
type: integer
id:
type: string
required:
- iat
type: object
type: array
name:
description: Name is a name for this role
type: string
policies:
description: Policies Stores a list of casbin formatted strings
that define access policies for the role in the project
items:
type: string
type: array
required:
- name
type: object
type: array
signatureKeys:
description: |-
SignatureKeys contains a list of PGP key IDs that commits in Git must be signed with in order to be allowed for sync
Deprecated: Use SourceIntegrity instead. SignatureKeys will be removed with the next major version.
items:
description: |-
SignatureKey is the specification of a key required to verify commit signatures with
Deprecated: Use SourceIntegrity instead. SignatureKeys will be removed with the next major version.
properties:
keyID:
description: The ID of the key in hexadecimal notation
type: string
required:
- keyID
type: object
type: array
sourceIntegrity:
description: |-
SourceIntegrity represents a constraint on manifest sources integrity to be met before they can be used.
Do not access directly, use EffectiveSourceIntegrity() for correct backwards compatibility handling.
properties:
git:
description: Git - policies for git source verification
properties:
policies:
items:
properties:
gpg:
description: Verify GPG commit/tag signatures
properties:
keys:
description: List of key IDs to trust. The keys
need to be in the repository server keyring.
items:
type: string
type: array
mode:
type: string
required:
- keys
- mode
type: object
repos:
description: List of repository criteria restricting
repositories the policy will apply to
items:
properties:
url:
description: URL specifier, glob.
type: string
required:
- url
type: object
type: array
required:
- gpg
- repos
type: object
type: array
required:
- policies
type: object
required:
- git
type: object
sourceNamespaces:
description: SourceNamespaces defines the namespaces application resources
are allowed to be created in
items:
type: string
type: array
sourceRepos:
description: SourceRepos contains list of repository URLs which can
be used for deployment
items:
type: string
type: array
syncWindows:
description: SyncWindows controls when syncs can be run for apps in
this project
items:
description: SyncWindow contains the kind, time, duration and attributes
that are used to assign the syncWindows to apps
properties:
andOperator:
description: UseAndOperator use AND operator for matching applications,
namespaces and clusters instead of the default OR operator
type: boolean
applications:
description: Applications contains a list of applications that
the window will apply to
items:
type: string
type: array
clusters:
description: Clusters contains a list of clusters that the window
will apply to
items:
type: string
type: array
description:
description: Description of the sync that will be applied to
the schedule, can be used to add any information such as a
ticket number for example
type: string
duration:
description: Duration is the amount of time the sync window
will be open
type: string
kind:
description: Kind defines if the window allows or blocks syncs
type: string
manualSync:
description: ManualSync enables manual syncs when they would
otherwise be blocked
type: boolean
namespaces:
description: Namespaces contains a list of namespaces that the
window will apply to
items:
type: string
type: array
schedule:
description: Schedule is the time the window will begin, specified
in cron format
type: string
syncOverrun:
description: |-
SyncOverrun allows ongoing syncs to continue in two scenarios:
For deny windows: allows syncs that started before the deny window became active to continue running
For allow windows: allows syncs that started during the allow window to continue after the window ends
type: boolean
timeZone:
description: TimeZone of the sync that will be applied to the
schedule
type: string
type: object
type: array
type: object
status:
description: AppProjectStatus contains status information for AppProject
CRs
properties:
jwtTokensByRole:
additionalProperties:
description: JWTTokens represents a list of JWT tokens
properties:
items:
items:
description: JWTToken holds the issuedAt and expiresAt values
of a token
properties:
exp:
format: int64
type: integer
iat:
format: int64
type: integer
id:
type: string
required:
- iat
type: object
type: array
type: object
description: JWTTokensByRole contains a list of JWT tokens issued
for a given role
type: object
type: object
required:
- metadata
- spec
type: object
served: true
storage: true