From 38864186396e14cf2f7b6c639e32c1026619e0b4 Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Fri, 22 May 2026 14:03:41 +0200 Subject: [PATCH 01/12] feat(argocd): add image pull secrets via oms beta install argod-repo-secret --- cli/cmd/argocd_repo_secret.go | 98 +++++++++++++ cli/cmd/beta_install.go | 1 + internal/installer/argocd_repo_secret.go | 79 ++++++++++ internal/installer/argocd_repo_secret_test.go | 137 ++++++++++++++++++ .../manifests/argocd/repo-secret.yaml.tpl | 15 ++ 5 files changed, 330 insertions(+) create mode 100644 cli/cmd/argocd_repo_secret.go create mode 100644 internal/installer/argocd_repo_secret.go create mode 100644 internal/installer/argocd_repo_secret_test.go create mode 100644 internal/installer/manifests/argocd/repo-secret.yaml.tpl diff --git a/cli/cmd/argocd_repo_secret.go b/cli/cmd/argocd_repo_secret.go new file mode 100644 index 00000000..971fc98d --- /dev/null +++ b/cli/cmd/argocd_repo_secret.go @@ -0,0 +1,98 @@ +// Copyright (c) Codesphere Inc. SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "context" + "fmt" + + packageio "github.com/codesphere-cloud/cs-go/pkg/io" + "github.com/codesphere-cloud/oms/internal/installer" + "github.com/spf13/cobra" +) + +// InstallArgoCDRepoSecretCmd represents the argocd-repo-secret command +type InstallArgoCDRepoSecretCmd struct { + cmd *cobra.Command + Opts InstallArgoCDRepoSecretOpts +} + +type InstallArgoCDRepoSecretOpts struct { + *GlobalOptions + Name string + URL string + RepoName string + Type string + Username string + Password string + EnableOCI bool + SecretType string +} + +func (c *InstallArgoCDRepoSecretCmd) RunE(_ *cobra.Command, args []string) error { + requiredFlags := map[string]string{ + "name": c.Opts.Name, + "url": c.Opts.URL, + "repo-name": c.Opts.RepoName, + "type": c.Opts.Type, + "username": c.Opts.Username, + "password": c.Opts.Password, + } + + for flagName, value := range requiredFlags { + if value == "" { + return fmt.Errorf("flag --%s is required", flagName) + } + } + + if c.Opts.Type != "helm" && c.Opts.Type != "git" { + return fmt.Errorf("flag --type must be either \"helm\" or \"git\", got %q", c.Opts.Type) + } + + cfg := installer.ArgoCDRepoSecretConfig{ + Name: c.Opts.Name, + URL: c.Opts.URL, + RepoName: c.Opts.RepoName, + Type: c.Opts.Type, + Username: c.Opts.Username, + Password: c.Opts.Password, + EnableOCI: c.Opts.EnableOCI, + SecretType: c.Opts.SecretType, + } + + repoSecret, err := installer.NewArgoCDRepoSecret(cfg) + if err != nil { + return fmt.Errorf("failed to initialize ArgoCD repo secret installer: %w", err) + } + + if err := repoSecret.Apply(context.Background()); err != nil { + return fmt.Errorf("failed to apply ArgoCD repo secret: %w", err) + } + + return nil +} + +func AddArgoCDRepoSecretCmd(parentCmd *cobra.Command, opts *GlobalOptions) { + repoSecret := InstallArgoCDRepoSecretCmd{ + cmd: &cobra.Command{ + Use: "argocd-repo-secret", + Short: "Create or update an ArgoCD repository secret", + Long: packageio.Long(`Create or update an ArgoCD repository secret for authenticating against Helm OCI registries or Git repositories.`), + Example: formatExamples("install argocd-repo-secret", []packageio.Example{ + {Cmd: "--name ghcr-codesphere-helm-repo --url ghcr.io/codesphere-cloud/charts --repo-name ghcr-codesphere --type helm --username CodesphereBot --password --enable-oci", Desc: "Create a Helm OCI registry secret"}, + {Cmd: "--name my-git-repo --url https://github.com/my-org --repo-name my-org --type git --username bot --password --secret-type repo-creds", Desc: "Create a git repo credentials secret"}, + }), + }, + } + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Name, "name", "", "Name of the Kubernetes Secret (metadata.name)") + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.URL, "url", "", "Repository URL (e.g. ghcr.io/codesphere-cloud/charts)") + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.RepoName, "repo-name", "", "Display name for the repository in ArgoCD") + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Type, "type", "", "Repository type: \"helm\" or \"git\"") + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Username, "username", "", "Username for repository authentication") + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Password, "password", "", "Password or token for repository authentication") + repoSecret.cmd.Flags().BoolVar(&repoSecret.Opts.EnableOCI, "enable-oci", false, "Enable OCI support (sets enableOCI: \"true\" in the secret)") + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.SecretType, "secret-type", "repository", "ArgoCD secret type label value (\"repository\" or \"repo-creds\")") + repoSecret.cmd.RunE = repoSecret.RunE + + AddCmd(parentCmd, repoSecret.cmd) +} diff --git a/cli/cmd/beta_install.go b/cli/cmd/beta_install.go index d9c56e20..5b7909bf 100644 --- a/cli/cmd/beta_install.go +++ b/cli/cmd/beta_install.go @@ -22,4 +22,5 @@ func AddBetaInstallCmd(rootCmd *cobra.Command, opts *GlobalOptions) { AddCmd(rootCmd, install.cmd) AddArgoCDCmd(install.cmd, opts) AddPCAppsCmd(install.cmd, opts) + AddArgoCDRepoSecretCmd(install.cmd, opts) } diff --git a/internal/installer/argocd_repo_secret.go b/internal/installer/argocd_repo_secret.go new file mode 100644 index 00000000..adbe53da --- /dev/null +++ b/internal/installer/argocd_repo_secret.go @@ -0,0 +1,79 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + +package installer + +import ( + "context" + _ "embed" + "fmt" + "log" + + k8s "github.com/codesphere-cloud/oms/internal/util" + "k8s.io/client-go/kubernetes" +) + +// ArgoCDRepoSecretConfig holds the parameters for creating an ArgoCD repository secret. +type ArgoCDRepoSecretConfig struct { + Name string // metadata.name of the Secret + URL string // repository URL (e.g. ghcr.io/codesphere-cloud/charts) + RepoName string // display name for ArgoCD (stringData.name) + Type string // repo type: "helm" or "git" + Username string // auth username + Password string // auth password/token + EnableOCI bool // whether to set enableOCI: "true" + SecretType string // argocd.argoproj.io/secret-type label value (default: "repository") +} + +// ArgoCDRepoSecret handles creating/updating ArgoCD repository secrets. +type ArgoCDRepoSecret struct { + Config ArgoCDRepoSecretConfig + Clientset kubernetes.Interface +} + +//go:embed manifests/argocd/repo-secret.yaml.tpl +var repoSecretTpl []byte + +// NewArgoCDRepoSecret creates a new ArgoCDRepoSecret installer. +func NewArgoCDRepoSecret(cfg ArgoCDRepoSecretConfig) (*ArgoCDRepoSecret, error) { + clientset, _, err := k8s.NewClients() + if err != nil { + return nil, fmt.Errorf("creating kubernetes clients: %w", err) + } + + return &ArgoCDRepoSecret{ + Config: cfg, + Clientset: clientset, + }, nil +} + +// Apply renders the template and creates or updates the ArgoCD repository secret. +func (r *ArgoCDRepoSecret) Apply(ctx context.Context) error { + log.Printf("Applying ArgoCD repository secret %q...\n", r.Config.Name) + + enableOCI := "false" + if r.Config.EnableOCI { + enableOCI = "true" + } + + rendered, err := k8s.RenderTemplate(repoSecretTpl, map[string]string{ + "SECRET_NAME": r.Config.Name, + "SECRET_TYPE": r.Config.SecretType, + "REPO_TYPE": r.Config.Type, + "REPO_URL": r.Config.URL, + "REPO_DISPLAY_NAME": r.Config.RepoName, + "USERNAME": r.Config.Username, + "PASSWORD": r.Config.Password, + "ENABLE_OCI": enableOCI, + }) + if err != nil { + return fmt.Errorf("rendering repo secret template: %w", err) + } + + if err := k8s.ApplySecretFromYAML(ctx, r.Clientset, rendered); err != nil { + return fmt.Errorf("applying repo secret %q: %w", r.Config.Name, err) + } + + fmt.Printf("Successfully applied ArgoCD repository secret %q\n", r.Config.Name) + return nil +} diff --git a/internal/installer/argocd_repo_secret_test.go b/internal/installer/argocd_repo_secret_test.go new file mode 100644 index 00000000..ade4d131 --- /dev/null +++ b/internal/installer/argocd_repo_secret_test.go @@ -0,0 +1,137 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + +package installer_test + +import ( + "context" + + "github.com/codesphere-cloud/oms/internal/installer" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + +var _ = Describe("ArgoCDRepoSecret.Apply", func() { + + var ( + fakeClient *fake.Clientset + ctx context.Context + ) + + BeforeEach(func() { + fakeClient = fake.NewSimpleClientset() + ctx = context.Background() + + // Ensure argocd namespace exists + _, err := fakeClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd"}, + }, metav1.CreateOptions{}) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("creating a new Helm OCI repository secret", func() { + It("creates the secret with all expected fields", func() { + repoSecret := &installer.ArgoCDRepoSecret{ + Config: installer.ArgoCDRepoSecretConfig{ + Name: "ghcr-codesphere-helm-repo", + URL: "ghcr.io/codesphere-cloud/charts", + RepoName: "ghcr-codesphere", + Type: "helm", + Username: "CodesphereBot", + Password: "super-secret-token", + EnableOCI: true, + SecretType: "repository", + }, + Clientset: fakeClient, + } + + err := repoSecret.Apply(ctx) + Expect(err).ToNot(HaveOccurred()) + + secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "ghcr-codesphere-helm-repo", metav1.GetOptions{}) + Expect(err).ToNot(HaveOccurred()) + Expect(secret.Labels).To(HaveKeyWithValue("argocd.argoproj.io/secret-type", "repository")) + Expect(secret.StringData["type"]).To(Equal("helm")) + Expect(secret.StringData["url"]).To(Equal("ghcr.io/codesphere-cloud/charts")) + Expect(secret.StringData["name"]).To(Equal("ghcr-codesphere")) + Expect(secret.StringData["username"]).To(Equal("CodesphereBot")) + Expect(secret.StringData["password"]).To(Equal("super-secret-token")) + Expect(secret.StringData["enableOCI"]).To(Equal("true")) + }) + }) + + Context("creating a git repo-creds secret", func() { + It("creates the secret with git type and repo-creds label", func() { + repoSecret := &installer.ArgoCDRepoSecret{ + Config: installer.ArgoCDRepoSecretConfig{ + Name: "my-git-repo", + URL: "https://github.com/my-org", + RepoName: "my-org", + Type: "git", + Username: "bot-user", + Password: "git-token", + EnableOCI: false, + SecretType: "repo-creds", + }, + Clientset: fakeClient, + } + + err := repoSecret.Apply(ctx) + Expect(err).ToNot(HaveOccurred()) + + secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "my-git-repo", metav1.GetOptions{}) + Expect(err).ToNot(HaveOccurred()) + Expect(secret.Labels).To(HaveKeyWithValue("argocd.argoproj.io/secret-type", "repo-creds")) + Expect(secret.StringData["type"]).To(Equal("git")) + Expect(secret.StringData["url"]).To(Equal("https://github.com/my-org")) + Expect(secret.StringData["name"]).To(Equal("my-org")) + Expect(secret.StringData["username"]).To(Equal("bot-user")) + Expect(secret.StringData["password"]).To(Equal("git-token")) + Expect(secret.StringData["enableOCI"]).To(Equal("false")) + }) + }) + + Context("updating an existing secret", func() { + It("updates the secret when it already exists", func() { + // Create initial secret + existing := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ghcr-codesphere-helm-repo", + Namespace: "argocd", + Labels: map[string]string{ + "argocd.argoproj.io/secret-type": "repository", + }, + }, + StringData: map[string]string{ + "password": "old-password", + }, + } + _, err := fakeClient.CoreV1().Secrets("argocd").Create(ctx, existing, metav1.CreateOptions{}) + Expect(err).ToNot(HaveOccurred()) + + repoSecret := &installer.ArgoCDRepoSecret{ + Config: installer.ArgoCDRepoSecretConfig{ + Name: "ghcr-codesphere-helm-repo", + URL: "ghcr.io/codesphere-cloud/charts", + RepoName: "ghcr-codesphere", + Type: "helm", + Username: "CodesphereBot", + Password: "new-password", + EnableOCI: true, + SecretType: "repository", + }, + Clientset: fakeClient, + } + + err = repoSecret.Apply(ctx) + Expect(err).ToNot(HaveOccurred()) + + secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "ghcr-codesphere-helm-repo", metav1.GetOptions{}) + Expect(err).ToNot(HaveOccurred()) + Expect(secret.StringData["password"]).To(Equal("new-password")) + }) + }) +}) diff --git a/internal/installer/manifests/argocd/repo-secret.yaml.tpl b/internal/installer/manifests/argocd/repo-secret.yaml.tpl new file mode 100644 index 00000000..1ccc011f --- /dev/null +++ b/internal/installer/manifests/argocd/repo-secret.yaml.tpl @@ -0,0 +1,15 @@ +# Generic ArgoCD repository secret +apiVersion: v1 +kind: Secret +metadata: + name: "${SECRET_NAME}" + namespace: argocd + labels: + argocd.argoproj.io/secret-type: ${SECRET_TYPE} +stringData: + type: ${REPO_TYPE} + url: ${REPO_URL} + name: ${REPO_DISPLAY_NAME} + username: ${USERNAME} + password: ${PASSWORD} + enableOCI: "${ENABLE_OCI}" From 80a7d0a8236226d7e0a3c1cb2264c292b2a17aad Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Fri, 22 May 2026 16:07:46 +0200 Subject: [PATCH 02/12] use env or stdin for password --- cli/cmd/argocd_repo_secret.go | 42 +++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/cli/cmd/argocd_repo_secret.go b/cli/cmd/argocd_repo_secret.go index 971fc98d..0f756fac 100644 --- a/cli/cmd/argocd_repo_secret.go +++ b/cli/cmd/argocd_repo_secret.go @@ -5,10 +5,12 @@ package cmd import ( "context" "fmt" + "os" packageio "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/codesphere-cloud/oms/internal/installer" "github.com/spf13/cobra" + "golang.org/x/term" ) // InstallArgoCDRepoSecretCmd represents the argocd-repo-secret command @@ -24,7 +26,6 @@ type InstallArgoCDRepoSecretOpts struct { RepoName string Type string Username string - Password string EnableOCI bool SecretType string } @@ -36,7 +37,6 @@ func (c *InstallArgoCDRepoSecretCmd) RunE(_ *cobra.Command, args []string) error "repo-name": c.Opts.RepoName, "type": c.Opts.Type, "username": c.Opts.Username, - "password": c.Opts.Password, } for flagName, value := range requiredFlags { @@ -49,13 +49,18 @@ func (c *InstallArgoCDRepoSecretCmd) RunE(_ *cobra.Command, args []string) error return fmt.Errorf("flag --type must be either \"helm\" or \"git\", got %q", c.Opts.Type) } + password, err := c.resolvePassword() + if err != nil { + return err + } + cfg := installer.ArgoCDRepoSecretConfig{ Name: c.Opts.Name, URL: c.Opts.URL, RepoName: c.Opts.RepoName, Type: c.Opts.Type, Username: c.Opts.Username, - Password: c.Opts.Password, + Password: password, EnableOCI: c.Opts.EnableOCI, SecretType: c.Opts.SecretType, } @@ -72,15 +77,39 @@ func (c *InstallArgoCDRepoSecretCmd) RunE(_ *cobra.Command, args []string) error return nil } +// resolvePassword reads the password from the OMS_REPO_PASSWORD environment variable, +// or prompts the user interactively if the env var is not set. +func (c *InstallArgoCDRepoSecretCmd) resolvePassword() (string, error) { + if pw := os.Getenv("OMS_REPO_PASSWORD"); len(pw) != 0 { + return pw, nil + } + + fmt.Print("Repository password/token: ") + pw, err := term.ReadPassword(int(os.Stdin.Fd())) + fmt.Println() + if err != nil { + return "", fmt.Errorf("failed to read password: %w", err) + } + if len(pw) == 0 { + return "", fmt.Errorf("password is required; set OMS_REPO_PASSWORD or enter it when prompted") + } + return string(pw), nil +} + func AddArgoCDRepoSecretCmd(parentCmd *cobra.Command, opts *GlobalOptions) { repoSecret := InstallArgoCDRepoSecretCmd{ cmd: &cobra.Command{ Use: "argocd-repo-secret", Short: "Create or update an ArgoCD repository secret", - Long: packageio.Long(`Create or update an ArgoCD repository secret for authenticating against Helm OCI registries or Git repositories.`), + Long: packageio.Long(`Create or update an ArgoCD repository secret for authenticating against + Helm OCI registries or Git repositories. + + The password is read from the OMS_REPO_PASSWORD environment variable. + If not set, it will be prompted interactively (hidden input). + You can also pipe the password via stdin: echo "token" | oms beta install argocd-repo-secret ...`), Example: formatExamples("install argocd-repo-secret", []packageio.Example{ - {Cmd: "--name ghcr-codesphere-helm-repo --url ghcr.io/codesphere-cloud/charts --repo-name ghcr-codesphere --type helm --username CodesphereBot --password --enable-oci", Desc: "Create a Helm OCI registry secret"}, - {Cmd: "--name my-git-repo --url https://github.com/my-org --repo-name my-org --type git --username bot --password --secret-type repo-creds", Desc: "Create a git repo credentials secret"}, + {Cmd: "--name ghcr-codesphere-helm-repo --url ghcr.io/codesphere-cloud/charts --repo-name ghcr-codesphere --type helm --username CodesphereBot --enable-oci", Desc: "Create a Helm OCI registry secret (prompts for password)"}, + {Cmd: "--name my-git-repo --url https://github.com/my-org --repo-name my-org --type git --username bot --secret-type repo-creds", Desc: "Create a git repo credentials secret (set OMS_REPO_PASSWORD env var beforehand)"}, }), }, } @@ -89,7 +118,6 @@ func AddArgoCDRepoSecretCmd(parentCmd *cobra.Command, opts *GlobalOptions) { repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.RepoName, "repo-name", "", "Display name for the repository in ArgoCD") repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Type, "type", "", "Repository type: \"helm\" or \"git\"") repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Username, "username", "", "Username for repository authentication") - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Password, "password", "", "Password or token for repository authentication") repoSecret.cmd.Flags().BoolVar(&repoSecret.Opts.EnableOCI, "enable-oci", false, "Enable OCI support (sets enableOCI: \"true\" in the secret)") repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.SecretType, "secret-type", "repository", "ArgoCD secret type label value (\"repository\" or \"repo-creds\")") repoSecret.cmd.RunE = repoSecret.RunE From b67ade3c492c7c49d9db0ce0a5895b80acbda116 Mon Sep 17 00:00:00 2001 From: Jcing95 <23337729+Jcing95@users.noreply.github.com> Date: Fri, 22 May 2026 14:15:58 +0000 Subject: [PATCH 03/12] chore(docs): Auto-update docs and licenses Signed-off-by: Jcing95 <23337729+Jcing95@users.noreply.github.com> --- docs/oms_beta_install.md | 1 + docs/oms_beta_install_argocd-repo-secret.md | 45 +++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 docs/oms_beta_install_argocd-repo-secret.md diff --git a/docs/oms_beta_install.md b/docs/oms_beta_install.md index d1c0d453..7b765757 100644 --- a/docs/oms_beta_install.md +++ b/docs/oms_beta_install.md @@ -12,5 +12,6 @@ Install beta components * [oms beta](oms_beta.md) - Commands for early testing * [oms beta install argocd](oms_beta_install_argocd.md) - Install an ArgoCD helm release +* [oms beta install argocd-repo-secret](oms_beta_install_argocd-repo-secret.md) - Create or update an ArgoCD repository secret * [oms beta install pc-apps](oms_beta_install_pc-apps.md) - Install the pc-applications Helm chart from a private OCI registry diff --git a/docs/oms_beta_install_argocd-repo-secret.md b/docs/oms_beta_install_argocd-repo-secret.md new file mode 100644 index 00000000..00c77afe --- /dev/null +++ b/docs/oms_beta_install_argocd-repo-secret.md @@ -0,0 +1,45 @@ +## oms beta install argocd-repo-secret + +Create or update an ArgoCD repository secret + +### Synopsis + +Create or update an ArgoCD repository secret for authenticating against +Helm OCI registries or Git repositories. + +The password is read from the OMS_REPO_PASSWORD environment variable. +If not set, it will be prompted interactively (hidden input). +You can also pipe the password via stdin: echo "token" | oms beta install argocd-repo-secret ... + +``` +oms beta install argocd-repo-secret [flags] +``` + +### Examples + +``` +# Create a Helm OCI registry secret (prompts for password) +$ oms install argocd-repo-secret --name ghcr-codesphere-helm-repo --url ghcr.io/codesphere-cloud/charts --repo-name ghcr-codesphere --type helm --username CodesphereBot --enable-oci + +# Create a git repo credentials secret (set OMS_REPO_PASSWORD env var beforehand) +$ oms install argocd-repo-secret --name my-git-repo --url https://github.com/my-org --repo-name my-org --type git --username bot --secret-type repo-creds + +``` + +### Options + +``` + --enable-oci Enable OCI support (sets enableOCI: "true" in the secret) + -h, --help help for argocd-repo-secret + --name string Name of the Kubernetes Secret (metadata.name) + --repo-name string Display name for the repository in ArgoCD + --secret-type string ArgoCD secret type label value ("repository" or "repo-creds") (default "repository") + --type string Repository type: "helm" or "git" + --url string Repository URL (e.g. ghcr.io/codesphere-cloud/charts) + --username string Username for repository authentication +``` + +### SEE ALSO + +* [oms beta install](oms_beta_install.md) - Install beta components + From 8b976ddcdecfa8d61a869617fae1e360a5cb4dec Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Tue, 26 May 2026 09:23:58 +0200 Subject: [PATCH 04/12] simplify argocd-repo-secret: only URL and username are customizable Hardcode all other values for the codesphere-helm-repo secret. The repo URL defaults to ghcr.io/codesphere-cloud/charts but can be overridden for mirrors. Username defaults to CodesphereBot. --- cli/cmd/argocd_repo_secret.go | 59 ++++++------------- docs/oms_beta_install.md | 2 +- docs/oms_beta_install_argocd-repo-secret.md | 30 +++++----- internal/installer/argocd_repo_secret_test.go | 49 +++++++-------- 4 files changed, 55 insertions(+), 85 deletions(-) diff --git a/cli/cmd/argocd_repo_secret.go b/cli/cmd/argocd_repo_secret.go index 0f756fac..a3dfa063 100644 --- a/cli/cmd/argocd_repo_secret.go +++ b/cli/cmd/argocd_repo_secret.go @@ -21,48 +21,25 @@ type InstallArgoCDRepoSecretCmd struct { type InstallArgoCDRepoSecretOpts struct { *GlobalOptions - Name string - URL string - RepoName string - Type string - Username string - EnableOCI bool - SecretType string + URL string + Username string } func (c *InstallArgoCDRepoSecretCmd) RunE(_ *cobra.Command, args []string) error { - requiredFlags := map[string]string{ - "name": c.Opts.Name, - "url": c.Opts.URL, - "repo-name": c.Opts.RepoName, - "type": c.Opts.Type, - "username": c.Opts.Username, - } - - for flagName, value := range requiredFlags { - if value == "" { - return fmt.Errorf("flag --%s is required", flagName) - } - } - - if c.Opts.Type != "helm" && c.Opts.Type != "git" { - return fmt.Errorf("flag --type must be either \"helm\" or \"git\", got %q", c.Opts.Type) - } - password, err := c.resolvePassword() if err != nil { return err } cfg := installer.ArgoCDRepoSecretConfig{ - Name: c.Opts.Name, + Name: "codesphere-helm-repo", URL: c.Opts.URL, - RepoName: c.Opts.RepoName, - Type: c.Opts.Type, + RepoName: "codesphere-helm-repo", + Type: "helm", Username: c.Opts.Username, Password: password, - EnableOCI: c.Opts.EnableOCI, - SecretType: c.Opts.SecretType, + EnableOCI: true, + SecretType: "repository", } repoSecret, err := installer.NewArgoCDRepoSecret(cfg) @@ -100,26 +77,24 @@ func AddArgoCDRepoSecretCmd(parentCmd *cobra.Command, opts *GlobalOptions) { repoSecret := InstallArgoCDRepoSecretCmd{ cmd: &cobra.Command{ Use: "argocd-repo-secret", - Short: "Create or update an ArgoCD repository secret", - Long: packageio.Long(`Create or update an ArgoCD repository secret for authenticating against - Helm OCI registries or Git repositories. + Short: "Create or update the Codesphere Helm repository secret in ArgoCD", + Long: packageio.Long(`Create or update the ArgoCD repository secret for authenticating against + the Codesphere Helm chart OCI registry. + + Use --url to point to a mirror of the registry if needed. The password is read from the OMS_REPO_PASSWORD environment variable. If not set, it will be prompted interactively (hidden input). You can also pipe the password via stdin: echo "token" | oms beta install argocd-repo-secret ...`), Example: formatExamples("install argocd-repo-secret", []packageio.Example{ - {Cmd: "--name ghcr-codesphere-helm-repo --url ghcr.io/codesphere-cloud/charts --repo-name ghcr-codesphere --type helm --username CodesphereBot --enable-oci", Desc: "Create a Helm OCI registry secret (prompts for password)"}, - {Cmd: "--name my-git-repo --url https://github.com/my-org --repo-name my-org --type git --username bot --secret-type repo-creds", Desc: "Create a git repo credentials secret (set OMS_REPO_PASSWORD env var beforehand)"}, + {Cmd: "", Desc: "Create the secret using defaults (prompts for password)"}, + {Cmd: "--url my-mirror.example.com/charts", Desc: "Use a mirrored registry URL"}, + {Cmd: "--url my-mirror.example.com/charts --username MyBot", Desc: "Use a mirrored registry with custom username"}, }), }, } - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Name, "name", "", "Name of the Kubernetes Secret (metadata.name)") - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.URL, "url", "", "Repository URL (e.g. ghcr.io/codesphere-cloud/charts)") - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.RepoName, "repo-name", "", "Display name for the repository in ArgoCD") - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Type, "type", "", "Repository type: \"helm\" or \"git\"") - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Username, "username", "", "Username for repository authentication") - repoSecret.cmd.Flags().BoolVar(&repoSecret.Opts.EnableOCI, "enable-oci", false, "Enable OCI support (sets enableOCI: \"true\" in the secret)") - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.SecretType, "secret-type", "repository", "ArgoCD secret type label value (\"repository\" or \"repo-creds\")") + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.URL, "url", "ghcr.io/codesphere-cloud/charts", "Helm OCI registry URL (customize for mirrors)") + repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Username, "username", "CodesphereBot", "Username for registry authentication") repoSecret.cmd.RunE = repoSecret.RunE AddCmd(parentCmd, repoSecret.cmd) diff --git a/docs/oms_beta_install.md b/docs/oms_beta_install.md index 7b765757..da3594df 100644 --- a/docs/oms_beta_install.md +++ b/docs/oms_beta_install.md @@ -12,6 +12,6 @@ Install beta components * [oms beta](oms_beta.md) - Commands for early testing * [oms beta install argocd](oms_beta_install_argocd.md) - Install an ArgoCD helm release -* [oms beta install argocd-repo-secret](oms_beta_install_argocd-repo-secret.md) - Create or update an ArgoCD repository secret +* [oms beta install argocd-repo-secret](oms_beta_install_argocd-repo-secret.md) - Create or update the Codesphere Helm repository secret in ArgoCD * [oms beta install pc-apps](oms_beta_install_pc-apps.md) - Install the pc-applications Helm chart from a private OCI registry diff --git a/docs/oms_beta_install_argocd-repo-secret.md b/docs/oms_beta_install_argocd-repo-secret.md index 00c77afe..dfaae3a7 100644 --- a/docs/oms_beta_install_argocd-repo-secret.md +++ b/docs/oms_beta_install_argocd-repo-secret.md @@ -1,11 +1,13 @@ ## oms beta install argocd-repo-secret -Create or update an ArgoCD repository secret +Create or update the Codesphere Helm repository secret in ArgoCD ### Synopsis -Create or update an ArgoCD repository secret for authenticating against -Helm OCI registries or Git repositories. +Create or update the ArgoCD repository secret for authenticating against +the Codesphere Helm chart OCI registry. + +Use --url to point to a mirror of the registry if needed. The password is read from the OMS_REPO_PASSWORD environment variable. If not set, it will be prompted interactively (hidden input). @@ -18,25 +20,23 @@ oms beta install argocd-repo-secret [flags] ### Examples ``` -# Create a Helm OCI registry secret (prompts for password) -$ oms install argocd-repo-secret --name ghcr-codesphere-helm-repo --url ghcr.io/codesphere-cloud/charts --repo-name ghcr-codesphere --type helm --username CodesphereBot --enable-oci +# Create the secret using defaults (prompts for password) +$ oms install argocd-repo-secret + +# Use a mirrored registry URL +$ oms install argocd-repo-secret --url my-mirror.example.com/charts -# Create a git repo credentials secret (set OMS_REPO_PASSWORD env var beforehand) -$ oms install argocd-repo-secret --name my-git-repo --url https://github.com/my-org --repo-name my-org --type git --username bot --secret-type repo-creds +# Use a mirrored registry with custom username +$ oms install argocd-repo-secret --url my-mirror.example.com/charts --username MyBot ``` ### Options ``` - --enable-oci Enable OCI support (sets enableOCI: "true" in the secret) - -h, --help help for argocd-repo-secret - --name string Name of the Kubernetes Secret (metadata.name) - --repo-name string Display name for the repository in ArgoCD - --secret-type string ArgoCD secret type label value ("repository" or "repo-creds") (default "repository") - --type string Repository type: "helm" or "git" - --url string Repository URL (e.g. ghcr.io/codesphere-cloud/charts) - --username string Username for repository authentication + -h, --help help for argocd-repo-secret + --url string Helm OCI registry URL (customize for mirrors) (default "ghcr.io/codesphere-cloud/charts") + --username string Username for registry authentication (default "CodesphereBot") ``` ### SEE ALSO diff --git a/internal/installer/argocd_repo_secret_test.go b/internal/installer/argocd_repo_secret_test.go index ade4d131..b98f4d28 100644 --- a/internal/installer/argocd_repo_secret_test.go +++ b/internal/installer/argocd_repo_secret_test.go @@ -32,13 +32,13 @@ var _ = Describe("ArgoCDRepoSecret.Apply", func() { Expect(err).ToNot(HaveOccurred()) }) - Context("creating a new Helm OCI repository secret", func() { + Context("creating the codesphere-helm-repo secret", func() { It("creates the secret with all expected fields", func() { repoSecret := &installer.ArgoCDRepoSecret{ Config: installer.ArgoCDRepoSecretConfig{ - Name: "ghcr-codesphere-helm-repo", + Name: "codesphere-helm-repo", URL: "ghcr.io/codesphere-cloud/charts", - RepoName: "ghcr-codesphere", + RepoName: "codesphere-helm-repo", Type: "helm", Username: "CodesphereBot", Password: "super-secret-token", @@ -51,30 +51,30 @@ var _ = Describe("ArgoCDRepoSecret.Apply", func() { err := repoSecret.Apply(ctx) Expect(err).ToNot(HaveOccurred()) - secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "ghcr-codesphere-helm-repo", metav1.GetOptions{}) + secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "codesphere-helm-repo", metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) Expect(secret.Labels).To(HaveKeyWithValue("argocd.argoproj.io/secret-type", "repository")) Expect(secret.StringData["type"]).To(Equal("helm")) Expect(secret.StringData["url"]).To(Equal("ghcr.io/codesphere-cloud/charts")) - Expect(secret.StringData["name"]).To(Equal("ghcr-codesphere")) + Expect(secret.StringData["name"]).To(Equal("codesphere-helm-repo")) Expect(secret.StringData["username"]).To(Equal("CodesphereBot")) Expect(secret.StringData["password"]).To(Equal("super-secret-token")) Expect(secret.StringData["enableOCI"]).To(Equal("true")) }) }) - Context("creating a git repo-creds secret", func() { - It("creates the secret with git type and repo-creds label", func() { + Context("using a mirrored registry URL", func() { + It("creates the secret with the custom URL", func() { repoSecret := &installer.ArgoCDRepoSecret{ Config: installer.ArgoCDRepoSecretConfig{ - Name: "my-git-repo", - URL: "https://github.com/my-org", - RepoName: "my-org", - Type: "git", - Username: "bot-user", - Password: "git-token", - EnableOCI: false, - SecretType: "repo-creds", + Name: "codesphere-helm-repo", + URL: "my-mirror.example.com/charts", + RepoName: "codesphere-helm-repo", + Type: "helm", + Username: "CodesphereBot", + Password: "mirror-token", + EnableOCI: true, + SecretType: "repository", }, Clientset: fakeClient, } @@ -82,15 +82,10 @@ var _ = Describe("ArgoCDRepoSecret.Apply", func() { err := repoSecret.Apply(ctx) Expect(err).ToNot(HaveOccurred()) - secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "my-git-repo", metav1.GetOptions{}) + secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "codesphere-helm-repo", metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) - Expect(secret.Labels).To(HaveKeyWithValue("argocd.argoproj.io/secret-type", "repo-creds")) - Expect(secret.StringData["type"]).To(Equal("git")) - Expect(secret.StringData["url"]).To(Equal("https://github.com/my-org")) - Expect(secret.StringData["name"]).To(Equal("my-org")) - Expect(secret.StringData["username"]).To(Equal("bot-user")) - Expect(secret.StringData["password"]).To(Equal("git-token")) - Expect(secret.StringData["enableOCI"]).To(Equal("false")) + Expect(secret.StringData["url"]).To(Equal("my-mirror.example.com/charts")) + Expect(secret.StringData["username"]).To(Equal("CodesphereBot")) }) }) @@ -99,7 +94,7 @@ var _ = Describe("ArgoCDRepoSecret.Apply", func() { // Create initial secret existing := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "ghcr-codesphere-helm-repo", + Name: "codesphere-helm-repo", Namespace: "argocd", Labels: map[string]string{ "argocd.argoproj.io/secret-type": "repository", @@ -114,9 +109,9 @@ var _ = Describe("ArgoCDRepoSecret.Apply", func() { repoSecret := &installer.ArgoCDRepoSecret{ Config: installer.ArgoCDRepoSecretConfig{ - Name: "ghcr-codesphere-helm-repo", + Name: "codesphere-helm-repo", URL: "ghcr.io/codesphere-cloud/charts", - RepoName: "ghcr-codesphere", + RepoName: "codesphere-helm-repo", Type: "helm", Username: "CodesphereBot", Password: "new-password", @@ -129,7 +124,7 @@ var _ = Describe("ArgoCDRepoSecret.Apply", func() { err = repoSecret.Apply(ctx) Expect(err).ToNot(HaveOccurred()) - secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "ghcr-codesphere-helm-repo", metav1.GetOptions{}) + secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "codesphere-helm-repo", metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) Expect(secret.StringData["password"]).To(Equal("new-password")) }) From 7db384274f3770c7185c38e8646cbe474b78f3ec Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Tue, 26 May 2026 09:35:09 +0200 Subject: [PATCH 05/12] address copilot --- cli/cmd/argocd_repo_secret.go | 22 +++++++++++++++++-- docs/oms_beta_install_argocd-repo-secret.md | 6 ++--- internal/installer/argocd_repo_secret_test.go | 2 ++ .../manifests/argocd/repo-secret.yaml.tpl | 14 ++++++------ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/cli/cmd/argocd_repo_secret.go b/cli/cmd/argocd_repo_secret.go index a3dfa063..81924c00 100644 --- a/cli/cmd/argocd_repo_secret.go +++ b/cli/cmd/argocd_repo_secret.go @@ -3,9 +3,11 @@ package cmd import ( + "bufio" "context" "fmt" "os" + "strings" packageio "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/codesphere-cloud/oms/internal/installer" @@ -55,12 +57,28 @@ func (c *InstallArgoCDRepoSecretCmd) RunE(_ *cobra.Command, args []string) error } // resolvePassword reads the password from the OMS_REPO_PASSWORD environment variable, -// or prompts the user interactively if the env var is not set. +// from stdin if piped, or prompts the user interactively if neither is available. func (c *InstallArgoCDRepoSecretCmd) resolvePassword() (string, error) { if pw := os.Getenv("OMS_REPO_PASSWORD"); len(pw) != 0 { return pw, nil } + // If stdin is not a terminal, read the password from the pipe. + if !term.IsTerminal(int(os.Stdin.Fd())) { + scanner := bufio.NewScanner(os.Stdin) + if scanner.Scan() { + pw := strings.TrimSpace(scanner.Text()) + if len(pw) == 0 { + return "", fmt.Errorf("password is required; received empty input from stdin") + } + return pw, nil + } + if err := scanner.Err(); err != nil { + return "", fmt.Errorf("failed to read password from stdin: %w", err) + } + return "", fmt.Errorf("password is required; no input received from stdin") + } + fmt.Print("Repository password/token: ") pw, err := term.ReadPassword(int(os.Stdin.Fd())) fmt.Println() @@ -86,7 +104,7 @@ func AddArgoCDRepoSecretCmd(parentCmd *cobra.Command, opts *GlobalOptions) { The password is read from the OMS_REPO_PASSWORD environment variable. If not set, it will be prompted interactively (hidden input). You can also pipe the password via stdin: echo "token" | oms beta install argocd-repo-secret ...`), - Example: formatExamples("install argocd-repo-secret", []packageio.Example{ + Example: formatExamples("beta install argocd-repo-secret", []packageio.Example{ {Cmd: "", Desc: "Create the secret using defaults (prompts for password)"}, {Cmd: "--url my-mirror.example.com/charts", Desc: "Use a mirrored registry URL"}, {Cmd: "--url my-mirror.example.com/charts --username MyBot", Desc: "Use a mirrored registry with custom username"}, diff --git a/docs/oms_beta_install_argocd-repo-secret.md b/docs/oms_beta_install_argocd-repo-secret.md index dfaae3a7..fac82670 100644 --- a/docs/oms_beta_install_argocd-repo-secret.md +++ b/docs/oms_beta_install_argocd-repo-secret.md @@ -21,13 +21,13 @@ oms beta install argocd-repo-secret [flags] ``` # Create the secret using defaults (prompts for password) -$ oms install argocd-repo-secret +$ oms beta install argocd-repo-secret # Use a mirrored registry URL -$ oms install argocd-repo-secret --url my-mirror.example.com/charts +$ oms beta install argocd-repo-secret --url my-mirror.example.com/charts # Use a mirrored registry with custom username -$ oms install argocd-repo-secret --url my-mirror.example.com/charts --username MyBot +$ oms beta install argocd-repo-secret --url my-mirror.example.com/charts --username MyBot ``` diff --git a/internal/installer/argocd_repo_secret_test.go b/internal/installer/argocd_repo_secret_test.go index b98f4d28..5d9478cb 100644 --- a/internal/installer/argocd_repo_secret_test.go +++ b/internal/installer/argocd_repo_secret_test.go @@ -14,6 +14,8 @@ import ( "k8s.io/client-go/kubernetes/fake" ) +// NOTE: Assertions use secret.StringData because the fake client does not perform +// the server-side StringData -> Data (base64) conversion that real Kubernetes does. var _ = Describe("ArgoCDRepoSecret.Apply", func() { var ( diff --git a/internal/installer/manifests/argocd/repo-secret.yaml.tpl b/internal/installer/manifests/argocd/repo-secret.yaml.tpl index 1ccc011f..b2dc6f7b 100644 --- a/internal/installer/manifests/argocd/repo-secret.yaml.tpl +++ b/internal/installer/manifests/argocd/repo-secret.yaml.tpl @@ -1,15 +1,15 @@ -# Generic ArgoCD repository secret +# Codesphere Helm repository secret for ArgoCD apiVersion: v1 kind: Secret metadata: name: "${SECRET_NAME}" namespace: argocd labels: - argocd.argoproj.io/secret-type: ${SECRET_TYPE} + argocd.argoproj.io/secret-type: "${SECRET_TYPE}" stringData: - type: ${REPO_TYPE} - url: ${REPO_URL} - name: ${REPO_DISPLAY_NAME} - username: ${USERNAME} - password: ${PASSWORD} + type: "${REPO_TYPE}" + url: "${REPO_URL}" + name: "${REPO_DISPLAY_NAME}" + username: "${USERNAME}" + password: "${PASSWORD}" enableOCI: "${ENABLE_OCI}" From fc955a8083f0c5ffa6c430429b7c49298c496d48 Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Tue, 26 May 2026 14:46:23 +0200 Subject: [PATCH 06/12] revert install secrets command + make git secrets and dc optional in argocd command --- cli/cmd/argocd.go | 86 +++++++---- cli/cmd/argocd_repo_secret.go | 119 ---------------- cli/cmd/beta_install.go | 1 - docs/oms_beta_install.md | 1 - docs/oms_beta_install_argocd-repo-secret.md | 45 ------ docs/oms_beta_install_argocd.md | 43 ++++-- internal/installer/argocd_repo_secret.go | 79 ----------- internal/installer/argocd_repo_secret_test.go | 134 ------------------ internal/installer/argocd_resources.go | 12 +- .../manifests/argocd/repo-secret.yaml.tpl | 15 -- 10 files changed, 96 insertions(+), 439 deletions(-) delete mode 100644 cli/cmd/argocd_repo_secret.go delete mode 100644 docs/oms_beta_install_argocd-repo-secret.md delete mode 100644 internal/installer/argocd_repo_secret.go delete mode 100644 internal/installer/argocd_repo_secret_test.go delete mode 100644 internal/installer/manifests/argocd/repo-secret.yaml.tpl diff --git a/cli/cmd/argocd.go b/cli/cmd/argocd.go index 65156d9d..a964134f 100644 --- a/cli/cmd/argocd.go +++ b/cli/cmd/argocd.go @@ -5,10 +5,12 @@ package cmd import ( "fmt" + "os" packageio "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/codesphere-cloud/oms/internal/installer" "github.com/spf13/cobra" + "golang.org/x/term" ) // InstallArgoCDCmd represents the argocd command @@ -19,31 +21,27 @@ type InstallArgoCDCmd struct { type InstallArgoCDOpts struct { *GlobalOptions - Version string - DatacenterId string - GitPassword string - RegistryPassword string - FullInstall bool - ForceConflicts bool - RepoURL string - ValueFiles []string + Version string + DatacenterId string + FullInstall bool + ForceConflicts bool + RepoURL string + ValueFiles []string } func (c *InstallArgoCDCmd) RunE(_ *cobra.Command, args []string) error { - if c.Opts.FullInstall { - requiredFlags := map[string]string{ - "git-password": c.Opts.GitPassword, - "registry-password": c.Opts.RegistryPassword, - "dc-id": c.Opts.DatacenterId, - } + var ociPassword, gitPassword string - for flagName, value := range requiredFlags { - if value == "" { - return fmt.Errorf("flag --%s is required when --deploy-dc-config is true", flagName) - } + if c.Opts.FullInstall { + pw, err := resolveOCIPassword() + if err != nil { + return err } + ociPassword = pw + gitPassword = os.Getenv("OMS_GIT_PASSWORD") } - install, err := installer.NewArgoCD(c.Opts.Version, c.Opts.DatacenterId, c.Opts.RegistryPassword, c.Opts.GitPassword, c.Opts.FullInstall, c.Opts.ForceConflicts, c.Opts.RepoURL, c.Opts.ValueFiles) + + install, err := installer.NewArgoCD(c.Opts.Version, c.Opts.DatacenterId, ociPassword, gitPassword, c.Opts.FullInstall, c.Opts.ForceConflicts, c.Opts.RepoURL, c.Opts.ValueFiles) if err != nil { return fmt.Errorf("failed to initialize ArgoCD installer: %w", err) } @@ -55,23 +53,57 @@ func (c *InstallArgoCDCmd) RunE(_ *cobra.Command, args []string) error { return nil } +// resolveOCIPassword reads the OCI registry password from the OMS_REGISTRY_PASSWORD +// environment variable, or prompts the user interactively if not set. +func resolveOCIPassword() (string, error) { + if pw := os.Getenv("OMS_REGISTRY_PASSWORD"); pw != "" { + return pw, nil + } + + if !term.IsTerminal(int(os.Stdin.Fd())) { + return "", fmt.Errorf("OMS_REGISTRY_PASSWORD must be set in non-interactive environments") + } + + fmt.Print("OCI registry password/token: ") + pw, err := term.ReadPassword(int(os.Stdin.Fd())) + fmt.Println() + if err != nil { + return "", fmt.Errorf("failed to read password: %w", err) + } + if len(pw) == 0 { + return "", fmt.Errorf("password is required; set OMS_REGISTRY_PASSWORD or enter it when prompted") + } + return string(pw), nil +} + func AddArgoCDCmd(parentCmd *cobra.Command, opts *GlobalOptions) { argocd := InstallArgoCDCmd{ cmd: &cobra.Command{ Use: "argocd", Short: "Install an ArgoCD helm release", - Long: packageio.Long(`Install an ArgoCD helm release`), - Example: formatExamples("install ArgoCD", []packageio.Example{ - {Cmd: "", Desc: "Install an ArgoCD helm release of chart https://argoproj.github.io/argo-helm/argo-cd "}, - {Cmd: "--version ", Desc: "Version of the ArgoCD helm chart to install"}, + Long: packageio.Long(`Install or upgrade the ArgoCD helm release. + + When --deploy-dc-config is set, Codesphere-managed resources are applied after + the chart install/upgrade: + - AppProjects (always) + - Helm OCI registry secret (always, requires OMS_REGISTRY_PASSWORD) + - Local cluster secret (only if --dc-id is provided) + - Git repo credentials (only if OMS_GIT_PASSWORD env var is set) + + Environment variables: + OMS_REGISTRY_PASSWORD Password/token for the Helm OCI registry (required for --deploy-dc-config) + OMS_GIT_PASSWORD Password/token for git repo access (optional)`), + Example: formatExamples("beta install argocd", []packageio.Example{ + {Cmd: "", Desc: "Install ArgoCD helm chart only"}, + {Cmd: "--version 7.8.0", Desc: "Install a specific chart version"}, + {Cmd: "--deploy-dc-config", Desc: "Install chart and apply Codesphere resources (prompts for OCI password)"}, + {Cmd: "--deploy-dc-config --dc-id 0", Desc: "Also register the local cluster as dc-0"}, }), }, } - argocd.cmd.Flags().StringVar(&argocd.Opts.GitPassword, "git-password", "", "Password/token to read from the git repo where ArgoCD Application manifests are stored") - argocd.cmd.Flags().StringVar(&argocd.Opts.RegistryPassword, "registry-password", "", "Password/token to read from the OCI registry (e.g. ghcr.io) where Helm chart artifacts are stored") - argocd.cmd.Flags().StringVar(&argocd.Opts.DatacenterId, "dc-id", "", "Codesphere Datacenter ID where this ArgoCD is installed") + argocd.cmd.Flags().StringVar(&argocd.Opts.DatacenterId, "dc-id", "", "Codesphere Datacenter ID (optional, registers local cluster in ArgoCD)") argocd.cmd.Flags().StringVarP(&argocd.Opts.Version, "version", "v", "", "Version of the ArgoCD helm chart to install") - argocd.cmd.Flags().BoolVar(&argocd.Opts.FullInstall, "deploy-dc-config", false, "Install Codesphere-managed resources (AppProjects, Repo Creds, ...) after installing the chart") + argocd.cmd.Flags().BoolVar(&argocd.Opts.FullInstall, "deploy-dc-config", false, "Apply Codesphere-managed resources (AppProjects, Repo Creds, ...) after installing the chart") argocd.cmd.Flags().StringArrayVarP(&argocd.Opts.ValueFiles, "values", "f", nil, "Specify values in a YAML file (can be specified multiple times)") argocd.cmd.Flags().BoolVar(&argocd.Opts.ForceConflicts, "force-conflicts", false, "Force field ownership conflicts during upgrade (sets server-side apply ForceConflicts)") argocd.cmd.Flags().StringVar(&argocd.Opts.RepoURL, "repo", "", "Helm chart repository URL; supports HTTP (default: https://argoproj.github.io/argo-helm) and OCI (e.g. oci://ghcr.io/argoproj/argo-helm)") diff --git a/cli/cmd/argocd_repo_secret.go b/cli/cmd/argocd_repo_secret.go deleted file mode 100644 index 81924c00..00000000 --- a/cli/cmd/argocd_repo_secret.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Codesphere Inc. SPDX-License-Identifier: Apache-2.0 - -package cmd - -import ( - "bufio" - "context" - "fmt" - "os" - "strings" - - packageio "github.com/codesphere-cloud/cs-go/pkg/io" - "github.com/codesphere-cloud/oms/internal/installer" - "github.com/spf13/cobra" - "golang.org/x/term" -) - -// InstallArgoCDRepoSecretCmd represents the argocd-repo-secret command -type InstallArgoCDRepoSecretCmd struct { - cmd *cobra.Command - Opts InstallArgoCDRepoSecretOpts -} - -type InstallArgoCDRepoSecretOpts struct { - *GlobalOptions - URL string - Username string -} - -func (c *InstallArgoCDRepoSecretCmd) RunE(_ *cobra.Command, args []string) error { - password, err := c.resolvePassword() - if err != nil { - return err - } - - cfg := installer.ArgoCDRepoSecretConfig{ - Name: "codesphere-helm-repo", - URL: c.Opts.URL, - RepoName: "codesphere-helm-repo", - Type: "helm", - Username: c.Opts.Username, - Password: password, - EnableOCI: true, - SecretType: "repository", - } - - repoSecret, err := installer.NewArgoCDRepoSecret(cfg) - if err != nil { - return fmt.Errorf("failed to initialize ArgoCD repo secret installer: %w", err) - } - - if err := repoSecret.Apply(context.Background()); err != nil { - return fmt.Errorf("failed to apply ArgoCD repo secret: %w", err) - } - - return nil -} - -// resolvePassword reads the password from the OMS_REPO_PASSWORD environment variable, -// from stdin if piped, or prompts the user interactively if neither is available. -func (c *InstallArgoCDRepoSecretCmd) resolvePassword() (string, error) { - if pw := os.Getenv("OMS_REPO_PASSWORD"); len(pw) != 0 { - return pw, nil - } - - // If stdin is not a terminal, read the password from the pipe. - if !term.IsTerminal(int(os.Stdin.Fd())) { - scanner := bufio.NewScanner(os.Stdin) - if scanner.Scan() { - pw := strings.TrimSpace(scanner.Text()) - if len(pw) == 0 { - return "", fmt.Errorf("password is required; received empty input from stdin") - } - return pw, nil - } - if err := scanner.Err(); err != nil { - return "", fmt.Errorf("failed to read password from stdin: %w", err) - } - return "", fmt.Errorf("password is required; no input received from stdin") - } - - fmt.Print("Repository password/token: ") - pw, err := term.ReadPassword(int(os.Stdin.Fd())) - fmt.Println() - if err != nil { - return "", fmt.Errorf("failed to read password: %w", err) - } - if len(pw) == 0 { - return "", fmt.Errorf("password is required; set OMS_REPO_PASSWORD or enter it when prompted") - } - return string(pw), nil -} - -func AddArgoCDRepoSecretCmd(parentCmd *cobra.Command, opts *GlobalOptions) { - repoSecret := InstallArgoCDRepoSecretCmd{ - cmd: &cobra.Command{ - Use: "argocd-repo-secret", - Short: "Create or update the Codesphere Helm repository secret in ArgoCD", - Long: packageio.Long(`Create or update the ArgoCD repository secret for authenticating against - the Codesphere Helm chart OCI registry. - - Use --url to point to a mirror of the registry if needed. - - The password is read from the OMS_REPO_PASSWORD environment variable. - If not set, it will be prompted interactively (hidden input). - You can also pipe the password via stdin: echo "token" | oms beta install argocd-repo-secret ...`), - Example: formatExamples("beta install argocd-repo-secret", []packageio.Example{ - {Cmd: "", Desc: "Create the secret using defaults (prompts for password)"}, - {Cmd: "--url my-mirror.example.com/charts", Desc: "Use a mirrored registry URL"}, - {Cmd: "--url my-mirror.example.com/charts --username MyBot", Desc: "Use a mirrored registry with custom username"}, - }), - }, - } - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.URL, "url", "ghcr.io/codesphere-cloud/charts", "Helm OCI registry URL (customize for mirrors)") - repoSecret.cmd.Flags().StringVar(&repoSecret.Opts.Username, "username", "CodesphereBot", "Username for registry authentication") - repoSecret.cmd.RunE = repoSecret.RunE - - AddCmd(parentCmd, repoSecret.cmd) -} diff --git a/cli/cmd/beta_install.go b/cli/cmd/beta_install.go index 5b7909bf..d9c56e20 100644 --- a/cli/cmd/beta_install.go +++ b/cli/cmd/beta_install.go @@ -22,5 +22,4 @@ func AddBetaInstallCmd(rootCmd *cobra.Command, opts *GlobalOptions) { AddCmd(rootCmd, install.cmd) AddArgoCDCmd(install.cmd, opts) AddPCAppsCmd(install.cmd, opts) - AddArgoCDRepoSecretCmd(install.cmd, opts) } diff --git a/docs/oms_beta_install.md b/docs/oms_beta_install.md index da3594df..d1c0d453 100644 --- a/docs/oms_beta_install.md +++ b/docs/oms_beta_install.md @@ -12,6 +12,5 @@ Install beta components * [oms beta](oms_beta.md) - Commands for early testing * [oms beta install argocd](oms_beta_install_argocd.md) - Install an ArgoCD helm release -* [oms beta install argocd-repo-secret](oms_beta_install_argocd-repo-secret.md) - Create or update the Codesphere Helm repository secret in ArgoCD * [oms beta install pc-apps](oms_beta_install_pc-apps.md) - Install the pc-applications Helm chart from a private OCI registry diff --git a/docs/oms_beta_install_argocd-repo-secret.md b/docs/oms_beta_install_argocd-repo-secret.md deleted file mode 100644 index fac82670..00000000 --- a/docs/oms_beta_install_argocd-repo-secret.md +++ /dev/null @@ -1,45 +0,0 @@ -## oms beta install argocd-repo-secret - -Create or update the Codesphere Helm repository secret in ArgoCD - -### Synopsis - -Create or update the ArgoCD repository secret for authenticating against -the Codesphere Helm chart OCI registry. - -Use --url to point to a mirror of the registry if needed. - -The password is read from the OMS_REPO_PASSWORD environment variable. -If not set, it will be prompted interactively (hidden input). -You can also pipe the password via stdin: echo "token" | oms beta install argocd-repo-secret ... - -``` -oms beta install argocd-repo-secret [flags] -``` - -### Examples - -``` -# Create the secret using defaults (prompts for password) -$ oms beta install argocd-repo-secret - -# Use a mirrored registry URL -$ oms beta install argocd-repo-secret --url my-mirror.example.com/charts - -# Use a mirrored registry with custom username -$ oms beta install argocd-repo-secret --url my-mirror.example.com/charts --username MyBot - -``` - -### Options - -``` - -h, --help help for argocd-repo-secret - --url string Helm OCI registry URL (customize for mirrors) (default "ghcr.io/codesphere-cloud/charts") - --username string Username for registry authentication (default "CodesphereBot") -``` - -### SEE ALSO - -* [oms beta install](oms_beta_install.md) - Install beta components - diff --git a/docs/oms_beta_install_argocd.md b/docs/oms_beta_install_argocd.md index 06a8e8d5..e08e3e1f 100644 --- a/docs/oms_beta_install_argocd.md +++ b/docs/oms_beta_install_argocd.md @@ -4,7 +4,18 @@ Install an ArgoCD helm release ### Synopsis -Install an ArgoCD helm release +Install or upgrade the ArgoCD helm release. + +When --deploy-dc-config is set, Codesphere-managed resources are applied after +the chart install/upgrade: + - AppProjects (always) + - Helm OCI registry secret (always, requires OMS_REGISTRY_PASSWORD) + - Local cluster secret (only if --dc-id is provided) + - Git repo credentials (only if OMS_GIT_PASSWORD env var is set) + +Environment variables: + OMS_REGISTRY_PASSWORD Password/token for the Helm OCI registry (required for --deploy-dc-config) + OMS_GIT_PASSWORD Password/token for git repo access (optional) ``` oms beta install argocd [flags] @@ -13,26 +24,30 @@ oms beta install argocd [flags] ### Examples ``` -# Install an ArgoCD helm release of chart https://argoproj.github.io/argo-helm/argo-cd -$ oms install ArgoCD +# Install ArgoCD helm chart only +$ oms beta install argocd + +# Install a specific chart version +$ oms beta install argocd --version 7.8.0 + +# Install chart and apply Codesphere resources (prompts for OCI password) +$ oms beta install argocd --deploy-dc-config -# Version of the ArgoCD helm chart to install -$ oms install ArgoCD --version +# Also register the local cluster as dc-0 +$ oms beta install argocd --deploy-dc-config --dc-id 0 ``` ### Options ``` - --dc-id string Codesphere Datacenter ID where this ArgoCD is installed - --deploy-dc-config Install Codesphere-managed resources (AppProjects, Repo Creds, ...) after installing the chart - --force-conflicts Force field ownership conflicts during upgrade (sets server-side apply ForceConflicts) - --git-password string Password/token to read from the git repo where ArgoCD Application manifests are stored - -h, --help help for argocd - --registry-password string Password/token to read from the OCI registry (e.g. ghcr.io) where Helm chart artifacts are stored - --repo string Helm chart repository URL; supports HTTP (default: https://argoproj.github.io/argo-helm) and OCI (e.g. oci://ghcr.io/argoproj/argo-helm) - -f, --values stringArray Specify values in a YAML file (can be specified multiple times) - -v, --version string Version of the ArgoCD helm chart to install + --dc-id string Codesphere Datacenter ID (optional, registers local cluster in ArgoCD) + --deploy-dc-config Apply Codesphere-managed resources (AppProjects, Repo Creds, ...) after installing the chart + --force-conflicts Force field ownership conflicts during upgrade (sets server-side apply ForceConflicts) + -h, --help help for argocd + --repo string Helm chart repository URL; supports HTTP (default: https://argoproj.github.io/argo-helm) and OCI (e.g. oci://ghcr.io/argoproj/argo-helm) + -f, --values stringArray Specify values in a YAML file (can be specified multiple times) + -v, --version string Version of the ArgoCD helm chart to install ``` ### SEE ALSO diff --git a/internal/installer/argocd_repo_secret.go b/internal/installer/argocd_repo_secret.go deleted file mode 100644 index adbe53da..00000000 --- a/internal/installer/argocd_repo_secret.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Codesphere Inc. -// SPDX-License-Identifier: Apache-2.0 - -package installer - -import ( - "context" - _ "embed" - "fmt" - "log" - - k8s "github.com/codesphere-cloud/oms/internal/util" - "k8s.io/client-go/kubernetes" -) - -// ArgoCDRepoSecretConfig holds the parameters for creating an ArgoCD repository secret. -type ArgoCDRepoSecretConfig struct { - Name string // metadata.name of the Secret - URL string // repository URL (e.g. ghcr.io/codesphere-cloud/charts) - RepoName string // display name for ArgoCD (stringData.name) - Type string // repo type: "helm" or "git" - Username string // auth username - Password string // auth password/token - EnableOCI bool // whether to set enableOCI: "true" - SecretType string // argocd.argoproj.io/secret-type label value (default: "repository") -} - -// ArgoCDRepoSecret handles creating/updating ArgoCD repository secrets. -type ArgoCDRepoSecret struct { - Config ArgoCDRepoSecretConfig - Clientset kubernetes.Interface -} - -//go:embed manifests/argocd/repo-secret.yaml.tpl -var repoSecretTpl []byte - -// NewArgoCDRepoSecret creates a new ArgoCDRepoSecret installer. -func NewArgoCDRepoSecret(cfg ArgoCDRepoSecretConfig) (*ArgoCDRepoSecret, error) { - clientset, _, err := k8s.NewClients() - if err != nil { - return nil, fmt.Errorf("creating kubernetes clients: %w", err) - } - - return &ArgoCDRepoSecret{ - Config: cfg, - Clientset: clientset, - }, nil -} - -// Apply renders the template and creates or updates the ArgoCD repository secret. -func (r *ArgoCDRepoSecret) Apply(ctx context.Context) error { - log.Printf("Applying ArgoCD repository secret %q...\n", r.Config.Name) - - enableOCI := "false" - if r.Config.EnableOCI { - enableOCI = "true" - } - - rendered, err := k8s.RenderTemplate(repoSecretTpl, map[string]string{ - "SECRET_NAME": r.Config.Name, - "SECRET_TYPE": r.Config.SecretType, - "REPO_TYPE": r.Config.Type, - "REPO_URL": r.Config.URL, - "REPO_DISPLAY_NAME": r.Config.RepoName, - "USERNAME": r.Config.Username, - "PASSWORD": r.Config.Password, - "ENABLE_OCI": enableOCI, - }) - if err != nil { - return fmt.Errorf("rendering repo secret template: %w", err) - } - - if err := k8s.ApplySecretFromYAML(ctx, r.Clientset, rendered); err != nil { - return fmt.Errorf("applying repo secret %q: %w", r.Config.Name, err) - } - - fmt.Printf("Successfully applied ArgoCD repository secret %q\n", r.Config.Name) - return nil -} diff --git a/internal/installer/argocd_repo_secret_test.go b/internal/installer/argocd_repo_secret_test.go deleted file mode 100644 index 5d9478cb..00000000 --- a/internal/installer/argocd_repo_secret_test.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Codesphere Inc. -// SPDX-License-Identifier: Apache-2.0 - -package installer_test - -import ( - "context" - - "github.com/codesphere-cloud/oms/internal/installer" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/fake" -) - -// NOTE: Assertions use secret.StringData because the fake client does not perform -// the server-side StringData -> Data (base64) conversion that real Kubernetes does. -var _ = Describe("ArgoCDRepoSecret.Apply", func() { - - var ( - fakeClient *fake.Clientset - ctx context.Context - ) - - BeforeEach(func() { - fakeClient = fake.NewSimpleClientset() - ctx = context.Background() - - // Ensure argocd namespace exists - _, err := fakeClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{Name: "argocd"}, - }, metav1.CreateOptions{}) - Expect(err).ToNot(HaveOccurred()) - }) - - Context("creating the codesphere-helm-repo secret", func() { - It("creates the secret with all expected fields", func() { - repoSecret := &installer.ArgoCDRepoSecret{ - Config: installer.ArgoCDRepoSecretConfig{ - Name: "codesphere-helm-repo", - URL: "ghcr.io/codesphere-cloud/charts", - RepoName: "codesphere-helm-repo", - Type: "helm", - Username: "CodesphereBot", - Password: "super-secret-token", - EnableOCI: true, - SecretType: "repository", - }, - Clientset: fakeClient, - } - - err := repoSecret.Apply(ctx) - Expect(err).ToNot(HaveOccurred()) - - secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "codesphere-helm-repo", metav1.GetOptions{}) - Expect(err).ToNot(HaveOccurred()) - Expect(secret.Labels).To(HaveKeyWithValue("argocd.argoproj.io/secret-type", "repository")) - Expect(secret.StringData["type"]).To(Equal("helm")) - Expect(secret.StringData["url"]).To(Equal("ghcr.io/codesphere-cloud/charts")) - Expect(secret.StringData["name"]).To(Equal("codesphere-helm-repo")) - Expect(secret.StringData["username"]).To(Equal("CodesphereBot")) - Expect(secret.StringData["password"]).To(Equal("super-secret-token")) - Expect(secret.StringData["enableOCI"]).To(Equal("true")) - }) - }) - - Context("using a mirrored registry URL", func() { - It("creates the secret with the custom URL", func() { - repoSecret := &installer.ArgoCDRepoSecret{ - Config: installer.ArgoCDRepoSecretConfig{ - Name: "codesphere-helm-repo", - URL: "my-mirror.example.com/charts", - RepoName: "codesphere-helm-repo", - Type: "helm", - Username: "CodesphereBot", - Password: "mirror-token", - EnableOCI: true, - SecretType: "repository", - }, - Clientset: fakeClient, - } - - err := repoSecret.Apply(ctx) - Expect(err).ToNot(HaveOccurred()) - - secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "codesphere-helm-repo", metav1.GetOptions{}) - Expect(err).ToNot(HaveOccurred()) - Expect(secret.StringData["url"]).To(Equal("my-mirror.example.com/charts")) - Expect(secret.StringData["username"]).To(Equal("CodesphereBot")) - }) - }) - - Context("updating an existing secret", func() { - It("updates the secret when it already exists", func() { - // Create initial secret - existing := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "codesphere-helm-repo", - Namespace: "argocd", - Labels: map[string]string{ - "argocd.argoproj.io/secret-type": "repository", - }, - }, - StringData: map[string]string{ - "password": "old-password", - }, - } - _, err := fakeClient.CoreV1().Secrets("argocd").Create(ctx, existing, metav1.CreateOptions{}) - Expect(err).ToNot(HaveOccurred()) - - repoSecret := &installer.ArgoCDRepoSecret{ - Config: installer.ArgoCDRepoSecretConfig{ - Name: "codesphere-helm-repo", - URL: "ghcr.io/codesphere-cloud/charts", - RepoName: "codesphere-helm-repo", - Type: "helm", - Username: "CodesphereBot", - Password: "new-password", - EnableOCI: true, - SecretType: "repository", - }, - Clientset: fakeClient, - } - - err = repoSecret.Apply(ctx) - Expect(err).ToNot(HaveOccurred()) - - secret, err := fakeClient.CoreV1().Secrets("argocd").Get(ctx, "codesphere-helm-repo", metav1.GetOptions{}) - Expect(err).ToNot(HaveOccurred()) - Expect(secret.StringData["password"]).To(Equal("new-password")) - }) - }) -}) diff --git a/internal/installer/argocd_resources.go b/internal/installer/argocd_resources.go index 25f8d655..5c5092db 100644 --- a/internal/installer/argocd_resources.go +++ b/internal/installer/argocd_resources.go @@ -60,16 +60,20 @@ func (a *argoCDResources) ApplyAll(ctx context.Context) error { return fmt.Errorf("applying app projects: %w", err) } - if err := a.applyLocalCluster(ctx); err != nil { - return fmt.Errorf("applying local cluster secret: %w", err) + if a.DatacenterId != "" { + if err := a.applyLocalCluster(ctx); err != nil { + return fmt.Errorf("applying local cluster secret: %w", err) + } } if err := a.applyHelmRegistrySecret(ctx); err != nil { return fmt.Errorf("applying helm registry secret: %w", err) } - if err := a.applyGitRepoSecret(ctx); err != nil { - return fmt.Errorf("applying git repo secret: %w", err) + if a.GitPassword != "" { + if err := a.applyGitRepoSecret(ctx); err != nil { + return fmt.Errorf("applying git repo secret: %w", err) + } } return nil diff --git a/internal/installer/manifests/argocd/repo-secret.yaml.tpl b/internal/installer/manifests/argocd/repo-secret.yaml.tpl deleted file mode 100644 index b2dc6f7b..00000000 --- a/internal/installer/manifests/argocd/repo-secret.yaml.tpl +++ /dev/null @@ -1,15 +0,0 @@ -# Codesphere Helm repository secret for ArgoCD -apiVersion: v1 -kind: Secret -metadata: - name: "${SECRET_NAME}" - namespace: argocd - labels: - argocd.argoproj.io/secret-type: "${SECRET_TYPE}" -stringData: - type: "${REPO_TYPE}" - url: "${REPO_URL}" - name: "${REPO_DISPLAY_NAME}" - username: "${USERNAME}" - password: "${PASSWORD}" - enableOCI: "${ENABLE_OCI}" From 896d541bd9e620249cfbc6a287c2db0fe28f69af Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Tue, 26 May 2026 15:07:00 +0200 Subject: [PATCH 07/12] address copilot --- internal/installer/argocd_resources.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/installer/argocd_resources.go b/internal/installer/argocd_resources.go index 5c5092db..14e4c1c0 100644 --- a/internal/installer/argocd_resources.go +++ b/internal/installer/argocd_resources.go @@ -66,6 +66,10 @@ func (a *argoCDResources) ApplyAll(ctx context.Context) error { } } + if a.OciPassword == "" { + return fmt.Errorf("OCI registry password is required but not set") + } + if err := a.applyHelmRegistrySecret(ctx); err != nil { return fmt.Errorf("applying helm registry secret: %w", err) } From 81ce5fab659c8d5c055dbde9c2b8cb8cfb152e8c Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Wed, 27 May 2026 07:24:28 +0200 Subject: [PATCH 08/12] address comment --- internal/installer/argocd_resources.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/installer/argocd_resources.go b/internal/installer/argocd_resources.go index 14e4c1c0..f6ac7021 100644 --- a/internal/installer/argocd_resources.go +++ b/internal/installer/argocd_resources.go @@ -6,6 +6,7 @@ package installer import ( "context" _ "embed" + "errors" "fmt" "log" @@ -67,7 +68,7 @@ func (a *argoCDResources) ApplyAll(ctx context.Context) error { } if a.OciPassword == "" { - return fmt.Errorf("OCI registry password is required but not set") + return errors.New("OCI registry password is required but not set") } if err := a.applyHelmRegistrySecret(ctx); err != nil { From d63632acc55d25778b169ea252ed0d54b2b71cdd Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Thu, 28 May 2026 14:48:05 +0200 Subject: [PATCH 09/12] make uri configurable --- cli/cmd/argocd.go | 7 ++++++- internal/installer/argocd.go | 6 ++++-- internal/installer/argocd_resources.go | 21 +++++++++++-------- .../manifests/argocd/repo-helm-oci.yaml.tpl | 2 +- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/cli/cmd/argocd.go b/cli/cmd/argocd.go index a964134f..002aeb3d 100644 --- a/cli/cmd/argocd.go +++ b/cli/cmd/argocd.go @@ -23,6 +23,7 @@ type InstallArgoCDOpts struct { *GlobalOptions Version string DatacenterId string + RegistryURL string FullInstall bool ForceConflicts bool RepoURL string @@ -41,7 +42,7 @@ func (c *InstallArgoCDCmd) RunE(_ *cobra.Command, args []string) error { gitPassword = os.Getenv("OMS_GIT_PASSWORD") } - install, err := installer.NewArgoCD(c.Opts.Version, c.Opts.DatacenterId, ociPassword, gitPassword, c.Opts.FullInstall, c.Opts.ForceConflicts, c.Opts.RepoURL, c.Opts.ValueFiles) + install, err := installer.NewArgoCD(c.Opts.Version, c.Opts.DatacenterId, ociPassword, c.Opts.RegistryURL, gitPassword, c.Opts.FullInstall, c.Opts.ForceConflicts, c.Opts.RepoURL, c.Opts.ValueFiles) if err != nil { return fmt.Errorf("failed to initialize ArgoCD installer: %w", err) } @@ -90,6 +91,9 @@ func AddArgoCDCmd(parentCmd *cobra.Command, opts *GlobalOptions) { - Local cluster secret (only if --dc-id is provided) - Git repo credentials (only if OMS_GIT_PASSWORD env var is set) + Use --registry-url to point to a custom or mirrored OCI registry (defaults + to ghcr.io/codesphere-cloud/charts). + Environment variables: OMS_REGISTRY_PASSWORD Password/token for the Helm OCI registry (required for --deploy-dc-config) OMS_GIT_PASSWORD Password/token for git repo access (optional)`), @@ -102,6 +106,7 @@ func AddArgoCDCmd(parentCmd *cobra.Command, opts *GlobalOptions) { }, } argocd.cmd.Flags().StringVar(&argocd.Opts.DatacenterId, "dc-id", "", "Codesphere Datacenter ID (optional, registers local cluster in ArgoCD)") + argocd.cmd.Flags().StringVar(&argocd.Opts.RegistryURL, "registry-url", "ghcr.io/codesphere-cloud/charts", "OCI registry URL for the Helm chart repository") argocd.cmd.Flags().StringVarP(&argocd.Opts.Version, "version", "v", "", "Version of the ArgoCD helm chart to install") argocd.cmd.Flags().BoolVar(&argocd.Opts.FullInstall, "deploy-dc-config", false, "Apply Codesphere-managed resources (AppProjects, Repo Creds, ...) after installing the chart") argocd.cmd.Flags().StringArrayVarP(&argocd.Opts.ValueFiles, "values", "f", nil, "Specify values in a YAML file (can be specified multiple times)") diff --git a/internal/installer/argocd.go b/internal/installer/argocd.go index 9a7b1afb..c76a70ab 100644 --- a/internal/installer/argocd.go +++ b/internal/installer/argocd.go @@ -23,6 +23,7 @@ type ArgoCD struct { Version string DatacenterId string OciPassword string + OciRegistryURL string GitPassword string FullInstall bool ForceConflicts bool @@ -32,13 +33,13 @@ type ArgoCD struct { Resources ArgoCDResources } -func NewArgoCD(version string, dcId string, passwordOCI string, passwordGit string, fullInstall bool, forceConflicts bool, repoURL string, valueFiles []string) (*ArgoCD, error) { +func NewArgoCD(version string, dcId string, passwordOCI string, ociRegistryURL string, passwordGit string, fullInstall bool, forceConflicts bool, repoURL string, valueFiles []string) (*ArgoCD, error) { helm, err := NewHelmClient("argocd") if err != nil { return nil, fmt.Errorf("init helm client failed: %w", err) } - resources, err := NewArgoCDResources(dcId, passwordOCI, passwordGit) + resources, err := NewArgoCDResources(dcId, passwordOCI, ociRegistryURL, passwordGit) if err != nil { return nil, fmt.Errorf("init argocd resources client failed: %w", err) } @@ -46,6 +47,7 @@ func NewArgoCD(version string, dcId string, passwordOCI string, passwordGit stri Version: version, DatacenterId: dcId, OciPassword: passwordOCI, + OciRegistryURL: ociRegistryURL, GitPassword: passwordGit, FullInstall: fullInstall, ForceConflicts: forceConflicts, diff --git a/internal/installer/argocd_resources.go b/internal/installer/argocd_resources.go index f6ac7021..b54284a7 100644 --- a/internal/installer/argocd_resources.go +++ b/internal/installer/argocd_resources.go @@ -24,23 +24,25 @@ type argoCDResources struct { clientset kubernetes.Interface dynClient dynamic.Interface - DatacenterId string - OciPassword string - GitPassword string + DatacenterId string + OciPassword string + OciRegistryURL string + GitPassword string } -func NewArgoCDResources(dataCenterId string, ociPassword string, gitPassword string) (ArgoCDResources, error) { +func NewArgoCDResources(dataCenterId string, ociPassword string, ociRegistryURL string, gitPassword string) (ArgoCDResources, error) { clientset, dynClient, err := k8s.NewClients() if err != nil { return nil, fmt.Errorf("creating kubernetes clients: %w", err) } return &argoCDResources{ - clientset: clientset, - dynClient: dynClient, - DatacenterId: dataCenterId, - OciPassword: ociPassword, - GitPassword: gitPassword, + clientset: clientset, + dynClient: dynClient, + DatacenterId: dataCenterId, + OciPassword: ociPassword, + OciRegistryURL: ociRegistryURL, + GitPassword: gitPassword, }, nil } @@ -119,6 +121,7 @@ func (a *argoCDResources) applyHelmRegistrySecret(ctx context.Context) error { log.Println("Applying helm registry secret... ") rendered, err := k8s.RenderTemplate(helmRegistryTpl, map[string]string{ "SECRET_CODESPHERE_OCI_READ": a.OciPassword, + "OCI_REGISTRY_URL": a.OciRegistryURL, }) if err != nil { return fmt.Errorf("rendering helm registry template: %w", err) diff --git a/internal/installer/manifests/argocd/repo-helm-oci.yaml.tpl b/internal/installer/manifests/argocd/repo-helm-oci.yaml.tpl index 7874c30a..2b1c9cb6 100644 --- a/internal/installer/manifests/argocd/repo-helm-oci.yaml.tpl +++ b/internal/installer/manifests/argocd/repo-helm-oci.yaml.tpl @@ -8,7 +8,7 @@ metadata: argocd.argoproj.io/secret-type: repository stringData: name: codesphere-charts - url: ghcr.io/codesphere-cloud/charts + url: "${OCI_REGISTRY_URL}" type: helm username: github password: "${SECRET_CODESPHERE_OCI_READ}" From 88cf040646c34a9fe5cd8365e4ee441b9a33d0fa Mon Sep 17 00:00:00 2001 From: Jcing95 <23337729+Jcing95@users.noreply.github.com> Date: Thu, 28 May 2026 12:51:08 +0000 Subject: [PATCH 10/12] chore(docs): Auto-update docs and licenses Signed-off-by: Jcing95 <23337729+Jcing95@users.noreply.github.com> --- docs/oms_beta_install_argocd.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/oms_beta_install_argocd.md b/docs/oms_beta_install_argocd.md index e08e3e1f..d13d4be9 100644 --- a/docs/oms_beta_install_argocd.md +++ b/docs/oms_beta_install_argocd.md @@ -13,6 +13,9 @@ the chart install/upgrade: - Local cluster secret (only if --dc-id is provided) - Git repo credentials (only if OMS_GIT_PASSWORD env var is set) +Use --registry-url to point to a custom or mirrored OCI registry (defaults +to ghcr.io/codesphere-cloud/charts). + Environment variables: OMS_REGISTRY_PASSWORD Password/token for the Helm OCI registry (required for --deploy-dc-config) OMS_GIT_PASSWORD Password/token for git repo access (optional) @@ -41,13 +44,14 @@ $ oms beta install argocd --deploy-dc-config --dc-id 0 ### Options ``` - --dc-id string Codesphere Datacenter ID (optional, registers local cluster in ArgoCD) - --deploy-dc-config Apply Codesphere-managed resources (AppProjects, Repo Creds, ...) after installing the chart - --force-conflicts Force field ownership conflicts during upgrade (sets server-side apply ForceConflicts) - -h, --help help for argocd - --repo string Helm chart repository URL; supports HTTP (default: https://argoproj.github.io/argo-helm) and OCI (e.g. oci://ghcr.io/argoproj/argo-helm) - -f, --values stringArray Specify values in a YAML file (can be specified multiple times) - -v, --version string Version of the ArgoCD helm chart to install + --dc-id string Codesphere Datacenter ID (optional, registers local cluster in ArgoCD) + --deploy-dc-config Apply Codesphere-managed resources (AppProjects, Repo Creds, ...) after installing the chart + --force-conflicts Force field ownership conflicts during upgrade (sets server-side apply ForceConflicts) + -h, --help help for argocd + --registry-url string OCI registry URL for the Helm chart repository (default "ghcr.io/codesphere-cloud/charts") + --repo string Helm chart repository URL; supports HTTP (default: https://argoproj.github.io/argo-helm) and OCI (e.g. oci://ghcr.io/argoproj/argo-helm) + -f, --values stringArray Specify values in a YAML file (can be specified multiple times) + -v, --version string Version of the ArgoCD helm chart to install ``` ### SEE ALSO From cc35405d6dacb15ca60d76514171843d63cc60ba Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Thu, 28 May 2026 16:06:40 +0200 Subject: [PATCH 11/12] remove blacklist all namespaces --- internal/installer/manifests/argocd/app-projects.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/installer/manifests/argocd/app-projects.yaml b/internal/installer/manifests/argocd/app-projects.yaml index 34c6e47c..9f4e0cff 100644 --- a/internal/installer/manifests/argocd/app-projects.yaml +++ b/internal/installer/manifests/argocd/app-projects.yaml @@ -85,6 +85,3 @@ spec: sourceRepos: [] sourceNamespaces: [] destinations: [] - namespaceResourceBlacklist: - - group: "*" - kind: "*" From 595f7a8926fde65537677765b91a541c8262f36b Mon Sep 17 00:00:00 2001 From: Jasin Aferkou Date: Fri, 29 May 2026 13:32:41 +0200 Subject: [PATCH 12/12] remove default project --- .../installer/manifests/argocd/app-projects.yaml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/internal/installer/manifests/argocd/app-projects.yaml b/internal/installer/manifests/argocd/app-projects.yaml index 9f4e0cff..f34917eb 100644 --- a/internal/installer/manifests/argocd/app-projects.yaml +++ b/internal/installer/manifests/argocd/app-projects.yaml @@ -72,16 +72,3 @@ spec: groups: - ops@codesphere.com - development@codesphere.com ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/refs/heads/main/argoproj.io/appproject_v1alpha1.json -# The default project has the most permissive settings and needs to be explicitly restricted -# https://argo-cd.readthedocs.io/en/stable/user-guide/projects/#the-default-project -apiVersion: argoproj.io/v1alpha1 -kind: AppProject -metadata: - name: default - namespace: argocd -spec: - sourceRepos: [] - sourceNamespaces: [] - destinations: []