1
0
mirror of https://github.com/quay/quay.git synced 2026-10-23 09:49:06 +03:00
Files
quay/internal/bootstrap/bootstrap.go
Harish Govindarajulu c525edb8ec PROJQUAY-13327: chore(cli): rename the quay binary to mirror-registry (#7252)
OMR 2.0.x users run `mirror-registry install|upgrade|uninstall`; OMR 3.0
shipped the same CLI as `quay`, which also collides with the Quay product
name. Rename the binary and its entrypoint so the command name is
consistent across versions.

- Makefile: GO_BINARY_NAME and GO_CMD_DIR; cmd/quay moves to
  cmd/mirror-registry.
- Dockerfile.mirror: build output and ENTRYPOINT.
- cmd package: BinaryName constant used for the root command and the
  version output; user-facing error hints that named `quay init` /
  `quay install` / `quay db upgrade` (now `mirror-registry install`, the command that upgrades an existing schema).
- ci-go.yaml: artifact name and every bin/quay invocation.

Unchanged: systemd unit quay.service, Quadlet quay.container, default
data directory /var/lib/quay, image quay.io/quay/quay-mirror, and the Go
module path.
2026-09-21 12:54:29 -04:00

79 lines
2.4 KiB
Go

// Package bootstrap provides first-run initialization for the registry.
package bootstrap
import (
"context"
"database/sql"
"errors"
"fmt"
"log/slog"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
"github.com/quay/quay/internal/dal/daldb"
)
// HasUsers reports whether the database already contains a login user.
func HasUsers(ctx context.Context, db *sql.DB) (bool, error) {
q := daldb.New(db)
count, err := q.CountUsers(ctx)
if err != nil {
return false, fmt.Errorf("count users: %w", err)
}
return count > 0, nil
}
// RequireAdminUser verifies that install-time provisioning has created a user
// and returns the first login username for standalone default authorization.
func RequireAdminUser(ctx context.Context, db *sql.DB) (string, error) {
var username string
err := db.QueryRowContext(ctx, `
SELECT username FROM "user"
WHERE organization = 0 AND robot = 0
ORDER BY id LIMIT 1
`).Scan(&username)
if err != nil {
if err == sql.ErrNoRows {
return "", fmt.Errorf("database has no users; run `mirror-registry init` or `mirror-registry install` to provision the initial administrator")
}
return "", fmt.Errorf("find initial administrator: %w", err)
}
return username, nil
}
// AdminUser creates the initial admin user if no users exist in the database.
// It returns true if a user was created, false if users already exist. Password
// generation and persistence belong to the one-shot installer, not the server.
func AdminUser(ctx context.Context, db *sql.DB, username, password string) (bool, error) {
q := daldb.New(db)
hasUsers, err := HasUsers(ctx, db)
if err != nil {
return false, err
}
if hasUsers {
return false, nil
}
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return false, errors.New("hash initial administrator password")
}
email := fmt.Sprintf("%s@localhost", username)
if _, err := q.CreateAdminUser(ctx, daldb.CreateAdminUserParams{
Uuid: sql.NullString{String: uuid.NewString(), Valid: true},
Username: username,
PasswordHash: sql.NullString{String: string(hash), Valid: true},
Email: email,
}); err != nil {
// Driver errors can include bound values, so do not propagate the
// password-derived hash to command-level logs.
return false, errors.New("create initial administrator")
}
slog.Info("admin user created", "username", username)
return true, nil
}