feat: complete MVP epics E7-E10 (provisioning, console proxy, audit, frontend)

This commit is contained in:
Philipp
2026-06-12 10:45:13 +02:00
parent 137c13fa98
commit ac30a19960
33 changed files with 3625 additions and 263 deletions
+172
View File
@@ -0,0 +1,172 @@
package sshkey
import (
"context"
"database/sql"
"errors"
)
type SQLRepository struct {
db *sql.DB
}
func NewSQLRepository(db *sql.DB) SQLRepository {
return SQLRepository{db: db}
}
func (r SQLRepository) List(ctx context.Context, profileID string, tenantID string) ([]SSHKey, bool, error) {
rows, err := r.db.QueryContext(ctx, `
select
sk.id::text,
sk.tenant_id::text,
sk.name,
sk.public_key,
sk.created_at
from public.tenants t
join public.memberships m
on m.tenant_id = t.id
and m.profile_id = $1
join public.ssh_keys sk
on sk.tenant_id = t.id
where t.id = $2
order by sk.created_at desc, sk.name asc
`, profileID, tenantID)
if err != nil {
return nil, false, err
}
defer rows.Close()
var keys []SSHKey
for rows.Next() {
var k SSHKey
if err := rows.Scan(&k.ID, &k.TenantID, &k.Name, &k.PublicKey, &k.CreatedAt); err != nil {
return nil, false, err
}
keys = append(keys, k)
}
if err := rows.Err(); err != nil {
return nil, false, err
}
if len(keys) == 0 {
exists, err := r.tenantExists(ctx, profileID, tenantID)
if err != nil {
return nil, false, err
}
return keys, exists, nil
}
return keys, true, nil
}
func (r SQLRepository) Get(ctx context.Context, profileID string, keyID string) (SSHKey, bool, error) {
var k SSHKey
err := r.db.QueryRowContext(ctx, `
select
sk.id::text,
sk.tenant_id::text,
sk.name,
sk.public_key,
sk.created_at
from public.ssh_keys sk
join public.memberships m
on m.tenant_id = sk.tenant_id
and m.profile_id = $1
where sk.id = $2
`, profileID, keyID).Scan(&k.ID, &k.TenantID, &k.Name, &k.PublicKey, &k.CreatedAt)
if errors.Is(err, sql.ErrNoRows) {
return SSHKey{}, false, nil
}
if err != nil {
return SSHKey{}, false, err
}
return k, true, nil
}
func (r SQLRepository) Create(ctx context.Context, profileID string, tenantID string, name string, publicKey string) (SSHKey, bool, error) {
exists, err := r.tenantMemberExists(ctx, profileID, tenantID)
if err != nil {
return SSHKey{}, false, err
}
if !exists {
return SSHKey{}, false, nil
}
var k SSHKey
err = r.db.QueryRowContext(ctx, `
insert into public.ssh_keys (tenant_id, name, public_key)
values ($1, $2, $3)
returning id::text, tenant_id::text, name, public_key, created_at
`, tenantID, name, publicKey).Scan(&k.ID, &k.TenantID, &k.Name, &k.PublicKey, &k.CreatedAt)
if err != nil {
return SSHKey{}, false, err
}
return k, true, nil
}
func (r SQLRepository) Delete(ctx context.Context, profileID string, keyID string) (bool, bool, error) {
var tenantID string
err := r.db.QueryRowContext(ctx, `
select sk.tenant_id::text
from public.ssh_keys sk
where sk.id = $1
`, keyID).Scan(&tenantID)
if errors.Is(err, sql.ErrNoRows) {
return false, false, nil
}
if err != nil {
return false, false, err
}
member, err := r.tenantMemberExists(ctx, profileID, tenantID)
if err != nil {
return false, false, err
}
if !member {
return false, true, nil
}
res, err := r.db.ExecContext(ctx, `
delete from public.ssh_keys
where id = $1
`, keyID)
if err != nil {
return false, false, err
}
rowsAffected, err := res.RowsAffected()
if err != nil {
return false, false, err
}
return rowsAffected > 0, true, nil
}
func (r SQLRepository) tenantExists(ctx context.Context, profileID string, tenantID string) (bool, error) {
var exists bool
err := r.db.QueryRowContext(ctx, `
select exists(
select 1
from public.tenants t
join public.memberships m
on m.tenant_id = t.id
and m.profile_id = $1
where t.id = $2
)
`, profileID, tenantID).Scan(&exists)
return exists, err
}
func (r SQLRepository) tenantMemberExists(ctx context.Context, profileID string, tenantID string) (bool, error) {
var exists bool
err := r.db.QueryRowContext(ctx, `
select exists(
select 1
from public.memberships
where profile_id = $1
and tenant_id = $2
)
`, profileID, tenantID).Scan(&exists)
return exists, err
}