All checks were successful
Check / check (pull_request) Successful in 3m34s
Add per-app registry credentials that are passed to Docker during image builds, allowing apps to use base images from private registries. - New registry_credentials table (migration 007) - RegistryCredential model with full CRUD operations - Docker client passes AuthConfigs to ImageBuild when credentials exist - Deploy service fetches app registry credentials before builds - Web UI section for managing registry credentials (add/edit/delete) - Comprehensive unit tests for model and auth config builder - README updated to list the feature
131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
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()
|
|
}
|