Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8b27054
feat: add command to create a test user for automated testing
OliverTrautvetter Apr 20, 2026
71a38c5
Merge branch 'main' into create_test_user
OliverTrautvetter Apr 20, 2026
99f814c
ref: fix linter
OliverTrautvetter Apr 20, 2026
2e0105b
ref: enhance test user creation logic and add password generation tests
OliverTrautvetter Apr 21, 2026
68e1313
Merge branch 'main' into create_test_user
OliverTrautvetter Apr 21, 2026
e6a7d70
Merge branch 'main' into create_test_user
OliverTrautvetter Apr 21, 2026
e26e487
chore(docs): Auto-update docs and licenses
OliverTrautvetter Apr 21, 2026
11b5982
ref: streamline test user creation and update environment variable re…
OliverTrautvetter Apr 22, 2026
b26d2c0
Merge branch 'main' into create_test_user
OliverTrautvetter Apr 22, 2026
dc580ca
chore(docs): Auto-update docs and licenses
OliverTrautvetter Apr 22, 2026
87808bd
ref: enhance error handling in RunCommand for quiet mode
OliverTrautvetter Apr 22, 2026
d99fd2f
Merge branch 'create_test_user' of https://github.com/codesphere-clou…
OliverTrautvetter Apr 22, 2026
d8e2d71
ref: streamline test user creation and remove unused password hashing…
OliverTrautvetter Apr 24, 2026
0835b78
Merge branch 'main' into create_test_user
OliverTrautvetter Apr 24, 2026
4db0b31
chore(docs): Auto-update docs and licenses
OliverTrautvetter Apr 24, 2026
f0b119f
Merge branch 'main' into create_test_user
OliverTrautvetter Apr 27, 2026
f3932a3
fix: update default value for registry-type flag in bootstrap GCP com…
OliverTrautvetter Apr 27, 2026
a2cc757
chore(docs): Auto-update docs and licenses
OliverTrautvetter Apr 27, 2026
0fe35ce
fix: remove unused salt parameter from hashSecret function
OliverTrautvetter Apr 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -653,9 +653,9 @@ License URL: https://github.com/ianlancetaylor/demangle/blob/96ee0021ea0f/LICENS

----------
Module: github.com/jedib0t/go-pretty/v6
Version: v6.7.9
Version: v6.7.10
License: MIT
License URL: https://github.com/jedib0t/go-pretty/blob/v6.7.9/LICENSE
License URL: https://github.com/jedib0t/go-pretty/blob/v6.7.10/LICENSE

----------
Module: github.com/jmoiron/sqlx
Expand Down Expand Up @@ -707,9 +707,9 @@ License URL: https://github.com/lann/ps/blob/62de8c46ede0/LICENSE

----------
Module: github.com/lib/pq
Version: v1.12.0
Version: v1.12.3
License: MIT
License URL: https://github.com/lib/pq/blob/v1.12.0/LICENSE
License URL: https://github.com/lib/pq/blob/v1.12.3/LICENSE

----------
Module: github.com/libopenstorage/secrets
Expand Down Expand Up @@ -743,9 +743,9 @@ License URL: https://github.com/mattn/go-isatty/blob/v0.0.20/LICENSE

----------
Module: github.com/mattn/go-runewidth
Version: v0.0.21
Version: v0.0.23
License: MIT
License URL: https://github.com/mattn/go-runewidth/blob/v0.0.21/LICENSE
License URL: https://github.com/mattn/go-runewidth/blob/v0.0.23/LICENSE

----------
Module: github.com/mitchellh/copystructure
Expand Down Expand Up @@ -905,9 +905,9 @@ License URL: https://github.com/prometheus/procfs/blob/v0.20.1/LICENSE

----------
Module: github.com/rook/rook/pkg/apis/ceph.rook.io
Version: v0.0.0-20260417181530-5bd05dcbd0db
Version: v0.0.0-20260424083917-b87c434ff9a9
License: Apache-2.0
License URL: https://github.com/rook/rook/blob/5bd05dcbd0db/pkg/apis/LICENSE
License URL: https://github.com/rook/rook/blob/b87c434ff9a9/pkg/apis/LICENSE

----------
Module: github.com/rubenv/sql-migrate
Expand Down Expand Up @@ -1211,9 +1211,9 @@ License URL: https://github.com/grpc/grpc-go/blob/v1.80.0/LICENSE

----------
Module: google.golang.org/protobuf
Version: v1.36.11
Version: v1.36.12-0.20260120151049-f2248ac996af
License: BSD-3-Clause
License URL: https://github.com/protocolbuffers/protobuf-go/blob/v1.36.11/LICENSE
License URL: https://github.com/protocolbuffers/protobuf-go/blob/f2248ac996af/LICENSE

----------
Module: gopkg.in/evanphx/json-patch.v4
Expand Down
7 changes: 5 additions & 2 deletions cli/cmd/bootstrap_gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func AddBootstrapGcpCmd(parent *cobra.Command, opts *GlobalOptions) {
flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.InstallHash, "install-hash", "", "Codesphere package hash to install (default: none)")
flags.StringArrayVarP(&bootstrapGcpCmd.CodesphereEnv.InstallSkipSteps, "install-skip-steps", "s", []string{}, "Installation steps to skip during Codesphere installation (optional)")
flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.RegistryUser, "registry-user", "", "Custom Registry username (only for GitHub registry type) (optional)")
flags.StringVar(&bootstrapGcpCmd.InputRegistryType, "registry-type", "local-container", "Container registry type to use (options: local-container, artifact-registry) (default: artifact-registry)")
flags.StringVar(&bootstrapGcpCmd.InputRegistryType, "registry-type", "local-container", "Container registry type to use (options: local-container, artifact-registry) (default: local-container)")
flags.StringArrayVar(&bootstrapGcpCmd.CodesphereEnv.Experiments, "experiments", gcp.DefaultExperiments, "Experiments to enable in Codesphere installation (optional)")
flags.StringArrayVar(&bootstrapGcpCmd.FeatureFlagList, "feature-flags", []string{}, "Feature flags to enable in Codesphere installation (optional)")

Expand All @@ -94,6 +94,7 @@ func AddBootstrapGcpCmd(parent *cobra.Command, opts *GlobalOptions) {
flags.BoolVar(&bootstrapGcpCmd.CodesphereEnv.WriteConfig, "write-config", true, "Write generated install config to file (default: true)")
flags.BoolVar(&bootstrapGcpCmd.CodesphereEnv.RecoverConfig, "recover-config", false, "Recover previously generated install config from the jumpbox. This will overwrite the local config! (default: false)")
flags.BoolVar(&bootstrapGcpCmd.SSHQuiet, "ssh-quiet", false, "Suppress SSH command output (default: false)")
flags.BoolVar(&bootstrapGcpCmd.CodesphereEnv.CreateTestUser, "create-test-user", false, "Create a test user with API token on the bootstrapped instance for smoke testing (default: false)")

flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.OpenBaoURI, "openbao-uri", "", "URI for OpenBao (optional)")
flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.OpenBaoEngine, "openbao-engine", "cs-secrets-engine", "OpenBao engine name (default: cs-secrets-engine)")
Expand Down Expand Up @@ -137,6 +138,7 @@ func (c *BootstrapGcpCmd) BootstrapGcp() error {
}

c.CodesphereEnv.RegistryType = gcp.RegistryType(c.InputRegistryType)
c.CodesphereEnv.OmsWorkdir = c.Env.GetOmsWorkdir()
if c.CodesphereEnv.GitHubPAT != "" {
c.CodesphereEnv.RegistryType = gcp.RegistryTypeGitHub
if c.CodesphereEnv.RegistryUser == "" {
Expand All @@ -163,7 +165,8 @@ func (c *BootstrapGcpCmd) BootstrapGcp() error {
}

log.Println("\n🎉🎉🎉 GCP infrastructure bootstrapped successfully!")
log.Printf("Access the jumpbox using:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY root@%s", bs.Env.Jumpbox.GetExternalIP())
log.Printf("Access the jumpbox using:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY -o SendEnv=OMS_PORTAL_API root@%s", bs.Env.Jumpbox.GetExternalIP())

if bs.Env.InstallVersion != "" {
log.Printf("Access Codesphere in your web browser at https://cs.%s", bs.Env.BaseDomain)

Expand Down
27 changes: 27 additions & 0 deletions cli/cmd/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Codesphere Inc.
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"github.com/codesphere-cloud/cs-go/pkg/io"
"github.com/spf13/cobra"
)

// CreateCmd represents the create command group
type CreateCmd struct {
cmd *cobra.Command
}

func AddCreateCmd(rootCmd *cobra.Command, opts *GlobalOptions) {
create := CreateCmd{
cmd: &cobra.Command{
Use: "create",
Short: "Create resources for Codesphere",
Long: io.Long(`Create resources for Codesphere installations, such as test users for automated testing.`),
},
}
AddCmd(rootCmd, create.cmd)

AddCreateTestUserCmd(create.cmd, opts)
}
69 changes: 69 additions & 0 deletions cli/cmd/create_test_user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Codesphere Inc.
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"fmt"

"github.com/spf13/cobra"

"github.com/codesphere-cloud/cs-go/pkg/io"
"github.com/codesphere-cloud/oms/internal/env"
"github.com/codesphere-cloud/oms/internal/testuser"
"github.com/codesphere-cloud/oms/internal/util"
)

type CreateTestUserCmd struct {
cmd *cobra.Command
Opts CreateTestUserOpts
Env env.Env
}

type CreateTestUserOpts struct {
*GlobalOptions
testuser.CreateTestUserOpts
}

func (c *CreateTestUserCmd) RunE(_ *cobra.Command, args []string) error {
result, err := testuser.CreateTestUser(c.Opts.CreateTestUserOpts)
if err != nil {
return fmt.Errorf("failed to create test user: %w", err)
}

testuser.LogAndPersistResult(result, c.Env.GetOmsWorkdir())

return nil
}

func AddCreateTestUserCmd(parent *cobra.Command, opts *GlobalOptions) {
c := CreateTestUserCmd{
cmd: &cobra.Command{
Use: "test-user",
Short: "Create a test user on a Codesphere database",
Long: io.Long(`Creates a test user with a hashed password and API token directly in a Codesphere
PostgreSQL database. The user can be used for automated smoke tests.

The command connects to the specified PostgreSQL instance and creates the necessary
database records (credentials, email confirmation, team, team membership, API token).

Credentials are displayed and saved to the OMS workdir as test-user.json.`),
},
Opts: CreateTestUserOpts{GlobalOptions: opts},
Env: env.NewEnv(),
}
c.cmd.RunE = c.RunE

flags := c.cmd.Flags()
flags.StringVar(&c.Opts.Host, "postgres-host", "", "PostgreSQL host address (required)")
flags.IntVar(&c.Opts.Port, "postgres-port", testuser.DefaultPort, "PostgreSQL port")
flags.StringVar(&c.Opts.User, "postgres-user", testuser.DefaultUser, "PostgreSQL username")
flags.StringVar(&c.Opts.Password, "postgres-password", "", "PostgreSQL password (required)")
flags.StringVar(&c.Opts.DBName, "postgres-db", testuser.DefaultDBName, "PostgreSQL database name")
flags.StringVar(&c.Opts.SSLMode, "ssl-mode", testuser.DefaultSSLMode, "PostgreSQL SSL mode")

util.MarkFlagRequired(c.cmd, "postgres-host")
util.MarkFlagRequired(c.cmd, "postgres-password")

AddCmd(parent, c.cmd)
}
Comment thread
OliverTrautvetter marked this conversation as resolved.
96 changes: 96 additions & 0 deletions cli/cmd/create_test_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) Codesphere Inc.
// SPDX-License-Identifier: Apache-2.0

package cmd_test

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/spf13/cobra"

"github.com/codesphere-cloud/oms/cli/cmd"
)

var _ = Describe("CreateTestUser", func() {
Context("AddCreateTestUserCmd", func() {
var createCmd cobra.Command
var opts *cmd.GlobalOptions

BeforeEach(func() {
createCmd = cobra.Command{}
opts = &cmd.GlobalOptions{}
})

It("accepts valid flags with all required flags set", func() {
createCmd.SetArgs([]string{
"test-user",
"--postgres-host", "localhost",
"--postgres-password", "secret",
})

cmd.AddCreateTestUserCmd(&createCmd, opts)

createCmd.Commands()[0].RunE = func(cmd *cobra.Command, args []string) error {
return nil
}

err := createCmd.Execute()
Expect(err).NotTo(HaveOccurred())
})

It("fails when --postgres-host is missing", func() {
createCmd.SetArgs([]string{
"test-user",
"--postgres-password", "secret",
})

cmd.AddCreateTestUserCmd(&createCmd, opts)

createCmd.Commands()[0].RunE = func(cmd *cobra.Command, args []string) error {
return nil
}

err := createCmd.Execute()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("postgres-host"))
})

It("fails when --postgres-password is missing", func() {
createCmd.SetArgs([]string{
"test-user",
"--postgres-host", "localhost",
})

cmd.AddCreateTestUserCmd(&createCmd, opts)

createCmd.Commands()[0].RunE = func(cmd *cobra.Command, args []string) error {
return nil
}

err := createCmd.Execute()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("postgres-password"))
})

It("accepts optional flags with custom values", func() {
createCmd.SetArgs([]string{
"test-user",
"--postgres-host", "db.example.com",
"--postgres-password", "secret",
"--postgres-port", "5433",
"--postgres-user", "admin",
"--postgres-db", "mydb",
"--ssl-mode", "require",
})

cmd.AddCreateTestUserCmd(&createCmd, opts)

createCmd.Commands()[0].RunE = func(cmd *cobra.Command, args []string) error {
return nil
}

err := createCmd.Execute()
Expect(err).NotTo(HaveOccurred())
})
})
})
3 changes: 3 additions & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ func GetRootCmd() *cobra.Command {
// Smoke test commands
AddSmoketestCmd(rootCmd, opts)

// Resource creation commands
AddCreateCmd(rootCmd, opts)

return rootCmd
}

Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ like downloading new versions.

* [oms beta](oms_beta.md) - Commands for early testing
* [oms build](oms_build.md) - Build and push images to a registry
* [oms create](oms_create.md) - Create resources for Codesphere
* [oms download](oms_download.md) - Download resources available through OMS
* [oms init](oms_init.md) - Initialize configuration files
* [oms install](oms_install.md) - Install Codesphere and other components
Expand Down
1 change: 1 addition & 0 deletions docs/oms.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ like downloading new versions.

* [oms beta](oms_beta.md) - Commands for early testing
* [oms build](oms_build.md) - Build and push images to a registry
* [oms create](oms_create.md) - Create resources for Codesphere
* [oms download](oms_download.md) - Download resources available through OMS
* [oms init](oms_init.md) - Initialize configuration files
* [oms install](oms_install.md) - Install Codesphere and other components
Expand Down
3 changes: 2 additions & 1 deletion docs/oms_beta_bootstrap-gcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ oms beta bootstrap-gcp [flags]
```
--base-domain string Base domain for Codesphere (required)
--billing-account string GCP Billing Account ID (required)
--create-test-user Create a test user with API token on the bootstrapped instance for smoke testing (default: false)
--custom-pg-ip string Custom PostgreSQL IP (optional)
--datacenter-id int Datacenter ID (default: 1) (default 1)
--dns-project-id string GCP Project ID for Cloud DNS (optional)
Expand Down Expand Up @@ -47,7 +48,7 @@ oms beta bootstrap-gcp [flags]
--project-ttl string Time to live for the GCP project. Cleanup workflows will remove it afterwards. (default: 2 hours) (default "2h")
--recover-config Recover previously generated install config from the jumpbox. This will overwrite the local config! (default: false)
--region string GCP Region (default: europe-west4) (default "europe-west4")
--registry-type string Container registry type to use (options: local-container, artifact-registry) (default: artifact-registry) (default "local-container")
--registry-type string Container registry type to use (options: local-container, artifact-registry) (default: local-container) (default "local-container")
--registry-user string Custom Registry username (only for GitHub registry type) (optional)
--secrets-dir string Directory for secrets (default: /etc/codesphere/secrets) (default "/etc/codesphere/secrets")
--secrets-file string Path to secrets files (optional) (default "prod.vault.yaml")
Expand Down
19 changes: 19 additions & 0 deletions docs/oms_create.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## oms create

Create resources for Codesphere

### Synopsis

Create resources for Codesphere installations, such as test users for automated testing.

### Options

```
-h, --help help for create
```

### SEE ALSO

* [oms](oms.md) - Codesphere Operations Management System (OMS)
* [oms create test-user](oms_create_test-user.md) - Create a test user on a Codesphere database

34 changes: 34 additions & 0 deletions docs/oms_create_test-user.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## oms create test-user

Create a test user on a Codesphere database

### Synopsis

Creates a test user with a hashed password and API token directly in a Codesphere
PostgreSQL database. The user can be used for automated smoke tests.

The command connects to the specified PostgreSQL instance and creates the necessary
database records (credentials, email confirmation, team, team membership, API token).

Credentials are displayed and saved to the OMS workdir as test-user.json.

```
oms create test-user [flags]
```

### Options

```
-h, --help help for test-user
--postgres-db string PostgreSQL database name (default "codesphere")
--postgres-host string PostgreSQL host address (required)
--postgres-password string PostgreSQL password (required)
--postgres-port int PostgreSQL port (default 5432)
--postgres-user string PostgreSQL username (default "postgres")
--ssl-mode string PostgreSQL SSL mode (default "disable")
```

### SEE ALSO

* [oms create](oms_create.md) - Create resources for Codesphere

Loading
Loading