These favicons still shipped the upstream artwork of whatever the surface was
scaffolded from, so a customer with a few of our products open read someone
else in every tab. They are @hanzo/logo favicon.{ico,svg,png} now, one source
for the geometry.
The structural gate refuses a tracked line naming the scaffold vendor, and it
had been refusing THIS repo for three days over one line: LLM.md quoting two
forge-side commit messages as EVIDENCE that GitHub's history was rewritten to
remove that name. The document was the last carrier of the string it documents.
The forensic point is the valuable part and it survives: the forge side names
the vendor where GitHub says "drop the scaffold vendor's build plugin" and
"Update the generated project template", a rewrite changes every sha, and that
is why merge-base finds no common ancestor and every count reads as
total-commits rather than divergence. None of that needs the literal name, so
the wording is now described rather than quoted.
Not an exemption in the gate. The gate was right — a rule that scans tracked
lines cannot know a line is about removal, and teaching it to would make it
weaker for the one case that matters.
Co-authored-by: Hanzo Dev <[email protected]>
The GitHub workflows are replaced by the canonical caller under .hanzo/workflows,
which is the only directory the forge collects. Every knob stays in /hanzo.yml, so
this file is the seven lines that name the shared reusable and nothing else -- the
same caller every other repo in the estate uses. GitHub Actions runs nothing here
now, by design.
hanzo.yml declared a gate with nothing to run it: github.com has no runner for
hanzo-build-linux-amd64, so a caller under .github/workflows can never be
scheduled. This is the ~7-line caller on the plane that can, pinned @v1.
Co-authored-by: Hanzo Dev <[email protected]>
House rule: /v1/ is the API prefix, everywhere, and /api/ is never added on
top of it. The api.* subdomain names the API; a path prefix restating it is
noise. This applies it to the whole route surface:
/api/v1/* -> /v1/* 106 proto annotations, 109 gateway patterns
/api/version -> /v1/version
/api/badge -> /v1/badge
/api/webhook -> /v1/webhook (server + applicationset controller)
/api/dex/* -> /v1/dex/* (constants; dex is built, not deployed)
The grpc-gateway .pb.gw.go files are generated, and the plugin toolchain is
not on this machine, so they were rewritten by a script that applies exactly
the transform codegen would: for /api/v1 paths, drop the leading "api"
literal-push opcode pair and decrement every LitPush(2,N)/Capture(5,N) pool
index; for /api/version, rename the segment. ConcatN(4,N) operands are
counts, not pool indexes, and are untouched. The .proto annotations moved in
the same commit, so the next real codegen run is a no-op against these files.
MustPattern panics at package init on a malformed pattern, so every rewritten
pattern is validated by any import of pkg/apiclient — those tests pass.
Also moved: assets/swagger.json (82 paths), the UI's two roots (apiRoot()
'/v1', version-service '/v1/version') and its two relative composers (app
logs download, badge panel), the five audit-pattern regexes in server.go, and
the tests that asserted the old paths. terminal_test's request URL claimed
/api/v1/terminal, a route that never existed — the handler is mounted at
/terminal; the fixture now says so.
NOT touched, deliberately: /api/v3 in GitHub Enterprise base-url examples
(GitHub's URL shape, not ours), util/vendored/kubeclientmetrics (parses the
KUBERNETES API server's /api/v1 paths), and util/http's cookie-path fixture
(arbitrary string exercising slash normalization).
go build ./... clean. Pre-existing failures in badge/session/webhook/account
tests reproduce identically on the parent commit (rebrand fallout — badge
colors, cookie name length, dex issuer) and are not made worse here.
External consumers checked: universe has zero references to cd.hanzo.ai/api;
the CLI speaks gRPC, not the REST gateway; UI and server ship in one image so
they move together.
Co-authored-by: Hanzo Dev <[email protected]>
v3.6.0-.2 could not start. hanzocd-server crash-looped:
fatal: Recovered from panic: nil pointer dereference
server.(*ArgoCDServer).Init -> server/server.go:554
configMapInformer and secretInformer were declared on the struct and Run() in
Init(), but never assigned anywhere in the repo. b2d7140a (delete the
notification subsystem) removed their construction —
secretInformer := k8s.NewSecretInformer(..., "cd-notifications-secret")
configMapInformer := k8s.NewConfigMapInformer(..., "cd-notifications-cm")
— which fed api.NewFactory for notifications and nothing else. The fields and
the two Run() calls survived the deletion, so both were nil at boot.
Deleted rather than reconstructed: they watched notification config, and there
is no notification subsystem to configure. We use hanzoai/notify.
Worth naming the class, because it is the third time tonight: a nil interface
field is valid Go, so `go build ./...` passed clean and said nothing. Same
shape as the Register* seams and the mounted globals — it compiles, and it
yields the zero value.
The "secret key does not exist in secret" warning on the preceding line is
unrelated; hanzocd-secret carries all five keys and works on sha-e1b9244.
Co-authored-by: Hanzo Dev <[email protected]>
The previous README was Argo CD's with Argo replaced by Hanzo, which put our
name on other people's work: "Unveil the Secret Ingredients of Continuous
Delivery at Enterprise Scale with Hanzo CD" is akuity's article about Argo CD,
and "Comparison of Hanzo CD, Spinnaker, Jenkins X, and Tekton" is inovex's.
Twenty-eight borrowed talks and posts, plus badges reading argoproj/argo-cd
release and coverage, an Artifact Hub link to their chart, their Twitter, Slack,
LinkedIn and Bluesky, their office hours calendar, their readthedocs, and a CNCF
Code of Conduct we are not governed by.
Replaced with what is actually true: what this fork changes (API group, binaries,
module, image, SSO, notifications), where it runs, how to build it, and that
releases are tagged rather than merged. Attribution to argoproj/argo-cd is kept
and made explicit — the engine is theirs; their community is not ours to claim.
Live demo link also dropped: it pointed at cd.apps.apps.hanzo.ai, a host that
does not resolve.
Co-authored-by: Hanzo Dev <[email protected]>
serverSideDiff finds the field set the CD controller owns by looking its manager
up by name. The live YAML fixtures were renamed to cd-controller; the
predicted-live JSON beside them still said argocd-controller, and the diff reads
both. Every server-side-diff case that asks "which fields are mine" failed with
"no managed fields found for manager: cd-controller" — not because the logic is
wrong, but because the two halves of the same fixture disagreed about who
applied it.
Seven JSON fixtures now name the same manager as the YAML they pair with.
pkg/diff goes green; the full gitops-engine module is 12/12.
Co-authored-by: Hanzo Dev <[email protected]>
The image carried LABEL org.opencontainers.image.source pointing at
github.com/argoproj/argo-cd, the upstream we forked from. GitHub links a
container package to the repo that label names; it cannot link to a repo outside
the org, so ghcr.io/hanzoai/cd was created UNLINKED, and an unlinked package
defaults to private. That is the whole reason v3.6.0 and v3.6.1 pushed fine and
could not be pulled:
failed to fetch anonymous token: 401 Unauthorized
Confirmed by comparing against the packages that work — every one of them is
linked and public:
deploy public repo=hanzoai/cd
cloud public repo=hanzoai/ai
cd PRIVATE repo=UNLINKED
So this was never a visibility setting someone forgot to flip; it was a stale
label doing exactly what it says. Fixing the label is the root cause, and it
keeps visibility derived from the repo rather than hand-set in a second place.
Also dropped the hanzocd-notifications symlink: the notification subsystem was
deleted in b2d7140a (we use hanzoai/notify), so the link pointed at a command
the binary no longer serves.
Co-authored-by: Hanzo Dev <[email protected]>
The Go side was renamed; the UI was not. It still compares resource groups
against 'argoproj.io' and writes argocd.argoproj.io/* annotations, so it and
the API no longer agree on what anything is called.
Worst of these is the finalizer. The controller injects and honors
resources-finalizer.apps.hanzo.ai; the create panel's cascade-delete checkbox
wrote resources-finalizer.argocd.argoproj.io. Ticking the box produced a
finalizer nothing reads — the user is told deletion will cascade, and it does
not. The live Applications already carry the apps.hanzo.ai form; only the UI
disagreed.
The group comparisons fail the same way, quietly: node.group === 'argoproj.io'
guards the ApplicationSet and Application branches in the resource tree,
detail panes, and extension tab lookup, and the backend now sends
apps.hanzo.ai, so those branches stopped being taken.
Values follow whichever constant owns them, rather than a blanket rename:
sync-wave / hook / deletion-approved cd.hanzo.ai/* (gitops-engine sync
vocabulary)
refresh / managed-by-url / link. / apps.hanzo.ai/* (application_annotations
notice. / pref. / group / apiVersion .go, common.go)
Untouched, because they are other people's CRDs and renaming them breaks
icon and subscription lookup for anyone running those products:
promoter.argoproj.io, notifications.argoproj.io.
tsc --noEmit clean; 22 suites / 263 tests / 32 snapshots pass.
Co-authored-by: Hanzo Dev <[email protected]>
go.mod still declared `module github.com/hanzoai/deploy` after the repo was
renamed. A Go module path is not cosmetic — it is the resolvable location. So
`go get github.com/hanzoai/cd` could not work, and anything importing this
module had to spell a name that no longer exists at that address. The build log
of v3.6.0 is where it surfaced: the compiler was still emitting
github.com/hanzoai/deploy/cmd/cd/commands.
3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile
and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to
ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from
the module path, replaced separately so neither could clobber the other.
go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean.
Co-authored-by: Hanzo Dev <[email protected]>
The repo is cd. The binaries are cd-*. The API group is apps.hanzo.ai, the
annotations are cd.hanzo.ai, the UI is cd.hanzo.ai. hanzo.yml was the last
place still saying `deploy` — the name from before the rename — so the
canonical build would have pushed the renamed engine to the old package.
universe infra/k8s/hanzo-cd/README.md has documented the engine as
ghcr.io/hanzoai/cd all along; this is the build target catching up to the
doc, not a new decision.
Also corrected in passing: the header still described the image as building
`notifications`, deleted in b2d7140a (we use hanzoai/notify), and still
called the repo hanzoai/deploy.
Removing v1alpha1 before deploying the binary that speaks v1 took the control
plane down on 2026-07-28: the running controller listed *v1alpha1.Application
against an API that no longer served it, CrashLooped, and 65 Applications plus
the ApplicationSet were lost.
The workloads survived only because the resources-finalizer never fired, and
recovery was possible only because everything was reconstructible from git.
Every CRD migration step was individually correct. The unchecked thing was
which version the running consumer speaks.
Co-authored-by: Hanzo Dev <[email protected]>
Two corrections on top of the naming pass, both found by checking the live
cluster rather than the source.
The rename had silently changed the user-facing annotation key from
argocd.argoproj.io/sync-wave to cd.argoproj.io/sync-wave — 63 live
Applications carry the old key, so deploying that would have ignored every
sync-wave and broken fleet deploy ordering. The key is now cd.hanzo.ai/*,
and universe 575650286 moves the ApplicationSet template that stamps it, so
the controller regenerates all 63 consistently.
The API group in code said argoproj.io/v1alpha1 in 157 places while the
cluster has served apps.hanzo.ai/v1alpha1 since 2026-07-23 (the CRDs are
applications.apps.hanzo.ai). Code now matches what is actually served.
The legacy applications.argoproj.io/app-name label had ZERO live users, so it
went with the rest. foo.argoproj.io test fixtures became foo.example.com —
arbitrary test domains should not carry a vendor name.
go build ./... exit 0.
Co-authored-by: Hanzo Dev <[email protected]>
The last argoproj dependency. notifications-engine was 49 files / 920K and
backed a subsystem with ZERO live workloads and ZERO Applications carrying
notification annotations, while hanzoai/notify v1.7.2 is already embedded in
cloud. Two ways to notify, one of them dead and pulling a dependency.
Deleted: cmd/cd-notification, notification_controller/, server/notification/,
util/notification/, the admin CLI command, hack/gen-catalog (generated the
service catalog), the gen-docs notification pass, and the wiring in
server.go and cmd/main.go.
github.com/argoproj now appears ZERO times in go.mod. Both live argoproj
dependencies are gone — pkg/v2 internalized in the previous commit,
notifications-engine deleted here.
go build ./... exit 0.
Co-authored-by: Hanzo Dev <[email protected]>
github.com/argoproj/pkg/v2 was one of two live argoproj dependencies. It is
11 files and 176K total, and we used five packages from it: grpc/http,
kubeclientmetrics, stats, sync, time.
Vendored into util/vendored/ and the dependency dropped from go.mod, so the
gRPC surface (2 references, in grpc-http/forwarders.go) is now ours to remove
on our own schedule rather than upstream's. Kubernetes client-go pulls gRPC
transitively regardless, so this is isolation — a realistic first step — not
a claim that gRPC is gone.
Internalized rather than forked to a shared repo because the only other
consumer, hanzo/gitops, has zero live deployments and zero dependents. A
second repo would be a second thing to version for one caller.
NOTICE carries the Apache-2.0 attribution. go build ./... exit 0.
Co-authored-by: Hanzo Dev <[email protected]>
The last Argo in the core type surface. It is also the seam that matters for
going KMS-native: repo- and cluster- credentials are read through ONE
interface with ONE constructor (NewDB), so a KMS-backed store is a second
implementation, not a rewrite of the 26 files that touch Secrets.
go build ./... exit 0.
Co-authored-by: Hanzo Dev <[email protected]>
Every command is cd-*: cd, cd-server, cd-repo-server,
cd-application-controller, cd-applicationset-controller, cd-cmp-server,
cd-commit-server, cd-dex, cd-git-ask-pass, cd-k8s-auth, cd-notification.
util/argo is util/cd; util/notification/argocd is util/notification/cd.
Preserved deliberately: github.com/argoproj/argocd-example-apps is an
EXTERNAL repo used as an e2e fixture, and notifications-engine + pkg/v2 are
real dependencies. Renaming a URL we do not own would break the tests.
Two bugs I made and caught, both from a careless sed:
- s/argo/cd/g turned 'argocd' into 'cdcd' in two directory names
- renaming the package declaration left every call site saying argo.X
go build ./... exit 0.
Co-authored-by: Hanzo Dev <[email protected]>
The fork was already ours everywhere that matters — our image, our IAM (dex
is not deployed), hanzo kv behind what the env still called REDIS. Only the
vocabulary was upstream's: ARGOCD_* across the Go, the manifests, the docs
and the plugin contract, and mkdocs still titled 'Argo CD' pointing at
argoproj/argo-cd.
ARGOCD_ -> CD_ and REDIS_ -> KV_ across 345 files, plus the 8 e2e/cmp
fixtures that assert the plugin env contract — those had to move with the
binary, which now emits CD_APP_NAME where they expected ARGOCD_APP_NAME.
Left alone deliberately, because renaming them would be wrong:
- util/helm/testdata/redis/ and gitops-engine/.../statefulset*.yaml are
fixtures for a THIRD-PARTY chart named redis, not our config
- util/kustomize/testdata/ likewise
- generated.proto regenerates from types.go, which is already clean
go build ./... exit 0.
LOCKSTEP: the live StatefulSet sets 47 ARGOCD_* names the binary no longer
reads. universe 4a5375735 carries the matching manifest change; they deploy
together or the controller falls back to defaults.
Co-authored-by: Hanzo Dev <[email protected]>
Carried off the legacy master branch before deleting it. master was the
pre-fork upstream line — it still declared Group = "argoproj.io" and
AnnotationKeyAppInstance = "argocd.argoproj.io/tracking-id", which is exactly
the identity being purged from this fork, so the branch itself had to go.
Its only two commits were this bump and a NOTICE attributing Argo CD upstream.
main already carries that NOTICE (Apache-2.0 attribution intact), so this line
was the sole thing that would have been lost. go build ./... exits 0 on 1.26.5.
Co-authored-by: Hanzo Dev <[email protected]>
main declared Group = "cd.hanzo.ai" while every CRD, all four Applications and
every tracked object in hanzo-k8s are on apps.hanzo.ai. There are no
cd.hanzo.ai CRDs anywhere, so a build from main binds nothing: the controller
comes up healthy, watches a group with no resources, and silently stops
reconciling the fleet. The deployed image (sha-e1b9244, all three components)
is the only reason this has not fired.
The rename reached further than the group. common.go:215 moved the ownership
annotation to cd.hanzo.ai/tracking-id while live objects carry
apps.hanzo.ai/tracking-id, and the finalizers moved too
(resources-finalizer.cd.hanzo.ai), which would leave existing objects holding
finalizers no running controller removes. Renaming a CRD group plus the
ownership annotation plus the finalizers is a data migration over every managed
object, not a source edit — shipping it as an edit is the defect. Reverting
restores the property that was lost: main is deployable at any time.
Mitigating only by luck: prune is false on all three automated Applications, so
the failure mode is "GitOps stops" rather than "GitOps deletes". Not a design.
Verified: no occurrence was a hostname (checked for the argocd.hanzo.ai-style
substring trap; none), 29 files, zero residual, register.go now byte-identical
to the deployed baseline. go build ./... exits 0. TestGetGlobalProjects and
TestGetAppOfAppSummary fail identically on unmodified origin/main — pre-existing,
not from this change.
If cd.hanzo.ai is still wanted, it needs CRD install, object conversion,
annotation and finalizer rewrite across every tracked resource, and RBAC —
executed deliberately, not carried in a source constant.
Co-authored-by: Hanzo Dev <[email protected]>
The repo carries the upstream LICENSE but no NOTICE, so nothing states which
project the code derives from or who holds copyright on it. Added in the same
form the other forks here use.
Co-authored-by: Hanzo Dev <[email protected]>
Superseded: the Hanzo GitHub App pushes a webhook, so the forge tracks GitHub
without a per-repo workflow. This file called git.hanzo.ai/api/v1/.../mirror-sync
— a Gitea API for a system we no longer drive — and would sit inert in every repo.
One mechanism, in one place, instead of ~350 copies of a cron.
git.hanzo.ai mirrors this repo by PULL on a ~10-minute interval, and arcd runs
CI/CD there — so every push waited out that interval before anything built.
This asks Gitea to pull HEAD immediately.
Latency only: the repo already mirrors via the App webhook, so a missing
HANZO_GIT_TOKEN or a failed curl is non-fatal and never fails the push.
Idempotent (mirror-sync just pulls HEAD) and concurrency-coalesced.
This workflow ran on a self-hosted actions-runner-controller pool. ARC is
decommissioned: CI executes inside git.hanzo.ai (Gitea Actions, .hanzo/workflows)
and delivery is cd.hanzo.ai reconciling the reviewed image pin in
hanzoai/universe. GitHub is a mirror and runs nothing.
Removed rather than repointed — there is no GitHub-side pool to move to, and
leaving it would keep ARC load-bearing.
This workflow ran on a self-hosted actions-runner-controller pool. ARC is
decommissioned: CI executes inside git.hanzo.ai (Gitea Actions, .hanzo/workflows)
and delivery is cd.hanzo.ai reconciling the reviewed image pin in
hanzoai/universe. GitHub is a mirror and runs nothing.
Removed rather than repointed — there is no GitHub-side pool to move to, and
leaving it would keep ARC load-bearing.
origin/main renamed the API group apps.hanzo.ai -> cd.hanzo.ai (apps.hanzo.ai
collided with the operator's App CR) but only in the overlays and CRDs; this
branch had renamed every object argocd-* -> hanzocd-* and regenerated the flat
install manifests against the old group.
Resolution keeps both axes orthogonal: the group is cd.hanzo.ai everywhere (it
must match common.go and the applicationset leader-election ID), the object
naming/labels stay hanzocd-* / part-of: hanzocd so the settings informer finds
its config. The generated install manifests are re-synced to the resolved
overlays, which also carries the group rename that upstream left out of them.
Go tree is byte-identical to origin/main.
apps.hanzo.ai collided head-on with the operator: its App CR already occupies
the resource name `apps.hanzo.ai` (plural `apps`, group `hanzo.ai`), so
`kubectl get apps.hanzo.ai` resolved to the operator's CR, not ours, and
`applications.apps.hanzo.ai` read as a stutter. cd.hanzo.ai gives the delivery
plane its own orthogonal group: applications/applicationsets/appprojects.cd.hanzo.ai
alongside the operator's apps.hanzo.ai. One name per concern.
Mechanically identical to e1b924475 (deploy.hanzo.ai -> apps.hanzo.ai): group
constant, every annotation/label/finalizer domain, the node.Group check, the
leader-election ID, the informer GVRs, RBAC apiGroups, and the 3 CRD manifests.
Also corrects the stale `+groupName=argoproj.io` marker in doc.go, which drove
nothing but misled every reader of this package, and the ArgoCD/argoproj naming
in the hanzo.yml cutover note.
Live cutover (CRD apply, CR re-home, image swap) stays separately greenlit —
hanzo.yml is deliberately build-only.
The server image expects the apps.hanzo.ai API group (register.go), hanzocd-*
config object names (common.go ArgoCDConfigMapName=hanzocd-cm, ...), and a
settings informer that selects app.kubernetes.io/part-of=hanzocd. The base
manifests still emitted argocd-* object names, part-of: argocd, and the stock
quay.io/argoproj/argocd image, so a fresh render produced config/RBAC the
running server cannot find (informer misses part-of=argocd config; server reads
hanzocd-cm but manifest creates argocd-cm) and would run the upstream image.
- Rename every object name and file argocd-* -> hanzocd-* (SA/Role/RoleBinding/
ClusterRole/ClusterRoleBinding/Service/Deployment/StatefulSet/ConfigMap/Secret/
NetworkPolicy), referential integrity preserved (roleRef/subjects/selectors/
configMapRef).
- Flip app.kubernetes.io/part-of: argocd -> hanzocd so the settings informer
finds the config objects.
- Point the image at ghcr.io/hanzoai/deploy (kustomize image transform +
container image refs).
- Match the hanzocd-cm ignoreResourceUpdates keys for the CD's own Application to
apps.hanzo.ai (argoproj.io_Application -> apps.hanzo.ai_Application; refresh/
hydrate annotation domains). External argoproj.io_Rollout / rollout.argoproj.io
/ notifications refs are left as-is.
- Drop the vestigial argoproj.io workflows create grant from hanzocd-server
ClusterRole (no Argo Workflows in this install).
- Regenerate the flat install manifests (install/namespace-install/core-install
and hydrator variants) from the corrected overlays.
RBAC now grants apps.hanzo.ai on applications/applicationsets/appprojects for
hanzocd-server and hanzocd-application-controller, so a fresh deploy keeps the
running apps.hanzo.ai server up. CRDs unchanged in group/kind/version (match the
live apps.hanzo.ai CRDs). Image-internal paths (/home/argocd, /usr/local/bin/
argocd) match the built image and are unchanged.
The CRD kind is Application, so apps.hanzo.ai reads naturally
(applications/applicationsets/appprojects.apps.hanzo.ai). Flips the group
constant (pkg/apis/application/register.go), all annotation/label/finalizer
domains (tracking-id, installation-id, secret-type, refresh, hydrate,
resources-finalizer, etc.), the node.Group check, and the 3 CRD manifests.
Module path github.com/hanzoai/deploy and hanzocd-* object names unchanged.
Co-authored-by: Hanzo Dev <[email protected]>
The askpass server sets GIT_ASKPASS=hanzocd + ARGOCD_BINARY_NAME=argocd-git-ask-pass;
cmd/main.go dispatches on ARGOCD_BINARY_NAME (env override) matched against
common.CommandGitAskPass. The rebrand moved the constant to hanzocd-git-ask-pass but
this hardcoded override value stayed argocd-git-ask-pass -> no match -> fell through to
the main CLI -> cobra tried to exec a plugin 'argocd-Username...' -> git auth failed.
Point the override at hanzocd-git-ask-pass. No symlink needed (dispatch is env-driven).
Co-authored-by: Hanzo Dev <[email protected]>
The git credential askpass hardcoded GIT_ASKPASS=argocd (util/askpass/server.go),
but the rebuilt image ships /usr/local/bin/hanzocd — so 'git fetch' failed with
'cannot run argocd' -> 'could not read Username for github.com' -> repo-server
could not render manifests. Point it (and the web-terminal LookPath, CLI config
dir, and session issuer) at hanzocd. This is the last runtime argocd binary ref.
Co-authored-by: Hanzo Dev <[email protected]>
The config-map/secret settings informer filtered on a HARDCODED literal
'app.kubernetes.io/part-of=argocd' (util/settings/settings.go partOfArgoCDSelector
+ isSettingsObject), not a common.go constant — so the rebuilt binary could not
discover hanzocd-cm/hanzocd-secret labeled part-of=hanzocd and fatal-crashed with
'configmap "hanzocd-cm" not found'. Point the selector + the admin cluster/repo
secret labels at part-of=hanzocd. Completes the operational rebrand.
Co-authored-by: Hanzo Dev <[email protected]>
set-vars always emitted quay_image_name, so the quay docker/login-action ran with
empty RELEASE_QUAY_* secrets → 'Username and password required' failed the build.
Empty quay_image_name skips the quay login and drops quay from TAGS; GHCR push
uses github.actor + GITHUB_TOKEN (packages: write).
Co-authored-by: Hanzo Dev <[email protected]>
* 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]>