Phase 11 implements the admin CLI with dual REST/gRPC transport, global flags (--server, --grpc, --token, --ca-cert, --json), and all commands: status, repo list/delete, policy CRUD, audit tail, gc trigger/status/reconcile, and snapshot. Phase 12 implements the HTMX web UI with chi router, session-based auth (HttpOnly/Secure/SameSite=Strict cookies), CSRF protection (HMAC-SHA256 signed double-submit), and pages for dashboard, repositories, manifest detail, policy management, and audit log. Security: CSRF via signed double-submit cookie, session cookies with HttpOnly/Secure/SameSite=Strict, TLS 1.3 minimum on all connections, form body size limits via http.MaxBytesReader. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
66 lines
1.4 KiB
Go
66 lines
1.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"text/tabwriter"
|
|
)
|
|
|
|
// formatSize returns a human-friendly representation of a byte count.
|
|
func formatSize(bytes int64) string {
|
|
const (
|
|
kb = 1024
|
|
mb = kb * 1024
|
|
gb = mb * 1024
|
|
tb = gb * 1024
|
|
)
|
|
|
|
switch {
|
|
case bytes >= tb:
|
|
return fmt.Sprintf("%.1f TB", float64(bytes)/float64(tb))
|
|
case bytes >= gb:
|
|
return fmt.Sprintf("%.1f GB", float64(bytes)/float64(gb))
|
|
case bytes >= mb:
|
|
return fmt.Sprintf("%.1f MB", float64(bytes)/float64(mb))
|
|
case bytes >= kb:
|
|
return fmt.Sprintf("%.1f KB", float64(bytes)/float64(kb))
|
|
default:
|
|
return fmt.Sprintf("%d B", bytes)
|
|
}
|
|
}
|
|
|
|
// printJSON marshals v as indented JSON and writes it to stdout.
|
|
func printJSON(v any) error {
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent("", " ")
|
|
return enc.Encode(v)
|
|
}
|
|
|
|
// printTable writes a table with the given headers and rows.
|
|
// Each row must have the same number of columns as headers.
|
|
func printTable(w io.Writer, headers []string, rows [][]string) {
|
|
tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
|
|
// Print header.
|
|
for i, h := range headers {
|
|
if i > 0 {
|
|
_, _ = fmt.Fprint(tw, "\t")
|
|
}
|
|
_, _ = fmt.Fprint(tw, h)
|
|
}
|
|
_, _ = fmt.Fprintln(tw)
|
|
|
|
// Print rows.
|
|
for _, row := range rows {
|
|
for i, col := range row {
|
|
if i > 0 {
|
|
_, _ = fmt.Fprint(tw, "\t")
|
|
}
|
|
_, _ = fmt.Fprint(tw, col)
|
|
}
|
|
_, _ = fmt.Fprintln(tw)
|
|
}
|
|
_ = tw.Flush()
|
|
}
|