package models import ( "context" "database/sql" "errors" "fmt" "sneak.berlin/go/upaas/internal/database" ) // RegistryCredential represents authentication credentials for a private Docker registry. type RegistryCredential struct { db *database.Database ID int64 AppID string Registry string Username string Password string //nolint:gosec // credential field required for registry auth } // NewRegistryCredential creates a new RegistryCredential with a database reference. func NewRegistryCredential(db *database.Database) *RegistryCredential { return &RegistryCredential{db: db} } // Save inserts or updates the registry credential in the database. func (r *RegistryCredential) Save(ctx context.Context) error { if r.ID == 0 { return r.insert(ctx) } return r.update(ctx) } // Delete removes the registry credential from the database. func (r *RegistryCredential) Delete(ctx context.Context) error { _, err := r.db.Exec(ctx, "DELETE FROM registry_credentials WHERE id = ?", r.ID) return err } func (r *RegistryCredential) insert(ctx context.Context) error { query := "INSERT INTO registry_credentials (app_id, registry, username, password) VALUES (?, ?, ?, ?)" result, err := r.db.Exec(ctx, query, r.AppID, r.Registry, r.Username, r.Password) if err != nil { return err } id, err := result.LastInsertId() if err != nil { return err } r.ID = id return nil } func (r *RegistryCredential) update(ctx context.Context) error { query := "UPDATE registry_credentials SET registry = ?, username = ?, password = ? WHERE id = ?" _, err := r.db.Exec(ctx, query, r.Registry, r.Username, r.Password, r.ID) return err } // FindRegistryCredential finds a registry credential by ID. // //nolint:nilnil // returning nil,nil is idiomatic for "not found" in Active Record func FindRegistryCredential( ctx context.Context, db *database.Database, id int64, ) (*RegistryCredential, error) { cred := NewRegistryCredential(db) row := db.QueryRow(ctx, "SELECT id, app_id, registry, username, password FROM registry_credentials WHERE id = ?", id, ) err := row.Scan(&cred.ID, &cred.AppID, &cred.Registry, &cred.Username, &cred.Password) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil } return nil, fmt.Errorf("scanning registry credential: %w", err) } return cred, nil } // FindRegistryCredentialsByAppID finds all registry credentials for an app. func FindRegistryCredentialsByAppID( ctx context.Context, db *database.Database, appID string, ) ([]*RegistryCredential, error) { query := ` SELECT id, app_id, registry, username, password FROM registry_credentials WHERE app_id = ? ORDER BY registry` rows, err := db.Query(ctx, query, appID) if err != nil { return nil, fmt.Errorf("querying registry credentials by app: %w", err) } defer func() { _ = rows.Close() }() var creds []*RegistryCredential for rows.Next() { cred := NewRegistryCredential(db) scanErr := rows.Scan( &cred.ID, &cred.AppID, &cred.Registry, &cred.Username, &cred.Password, ) if scanErr != nil { return nil, scanErr } creds = append(creds, cred) } return creds, rows.Err() }