This commit is contained in:
2026-07-25 14:51:48 -05:00
parent 1ea21c065e
commit 69cc236635
18 changed files with 770 additions and 106 deletions
+122 -26
View File
@@ -26,6 +26,11 @@ func (s *Server) handlePortal(w http.ResponseWriter, r *http.Request) {
http.Error(w, "unable to list authorizations", http.StatusInternalServerError)
return
}
actions, err := s.listActions(r)
if err != nil {
http.Error(w, "unable to list installer actions", http.StatusInternalServerError)
return
}
auditEvents, err := s.listAuditEvents(r)
if err != nil {
http.Error(w, "unable to list audit events", http.StatusInternalServerError)
@@ -38,6 +43,7 @@ func (s *Server) handlePortal(w http.ResponseWriter, r *http.Request) {
Authorizations: authorizations,
AuditEvents: auditEvents,
Packages: packages,
Actions: actions,
NewCode: r.URL.Query().Get("code"),
DefaultHostLimit: s.cfg.DefaultHostLimit,
DefaultDuration: strconv.Itoa(int(s.cfg.DefaultDuration.Hours())),
@@ -45,6 +51,29 @@ func (s *Server) handlePortal(w http.ResponseWriter, r *http.Request) {
})
}
func (s *Server) listActions(r *http.Request) ([]actionRecord, error) {
rows, err := s.db.QueryContext(
r.Context(),
`SELECT slug, display_name, enabled
FROM installer_actions
ORDER BY sort_order, display_name`,
)
if err != nil {
return nil, err
}
defer rows.Close()
var records []actionRecord
for rows.Next() {
var record actionRecord
if err := rows.Scan(&record.Slug, &record.DisplayName, &record.Enabled); err != nil {
return nil, err
}
records = append(records, record)
}
return records, rows.Err()
}
func (s *Server) listAuditEvents(r *http.Request) ([]auditRecord, error) {
rows, err := s.db.QueryContext(
r.Context(),
@@ -113,16 +142,25 @@ func (s *Server) listAuthorizations(r *http.Request) ([]authorizationRecord, err
rows, err := s.db.QueryContext(
r.Context(),
`SELECT a.id, a.code_hint, a.created_by, a.customer_label,
a.host_limit, COUNT(DISTINCT h.id), a.created_at,
a.expires_at, a.revoked_at,
COALESCE(GROUP_CONCAT(DISTINCT p.display_name
ORDER BY p.display_name SEPARATOR ', '), '')
a.host_limit,
(SELECT COUNT(*) FROM authorization_hosts h
WHERE h.authorization_id = a.id),
a.created_at, a.expires_at, a.revoked_at,
COALESCE((
SELECT GROUP_CONCAT(ap.display_name
ORDER BY ap.display_name SEPARATOR ', ')
FROM authorization_packages ap
WHERE ap.authorization_id = a.id
), ''),
COALESCE((
SELECT GROUP_CONCAT(ia.display_name
ORDER BY ia.sort_order, ia.display_name SEPARATOR ', ')
FROM authorization_actions aa
JOIN installer_actions ia ON ia.slug = aa.action_slug
WHERE aa.authorization_id = a.id
), '')
FROM authorizations a
LEFT JOIN authorization_hosts h ON h.authorization_id = a.id
LEFT JOIN authorization_packages ap ON ap.authorization_id = a.id
LEFT JOIN packages p ON p.id = ap.package_id
WHERE a.created_at > UTC_TIMESTAMP(6) - INTERVAL 30 DAY
GROUP BY a.id
ORDER BY a.created_at DESC
LIMIT 100`,
)
@@ -144,6 +182,7 @@ func (s *Server) listAuthorizations(r *http.Request) ([]authorizationRecord, err
&record.ExpiresAt,
&record.RevokedAt,
&record.Packages,
&record.Actions,
); err != nil {
return nil, err
}
@@ -165,8 +204,9 @@ func (s *Server) handleCreateAuthorization(w http.ResponseWriter, r *http.Reques
return
}
packageIDs := r.Form["package_id"]
if len(packageIDs) == 0 {
http.Error(w, "select at least one package", http.StatusBadRequest)
actionSlugs := r.Form["action_slug"]
if len(packageIDs) == 0 && len(actionSlugs) == 0 {
http.Error(w, "select at least one package or installer action", http.StatusBadRequest)
return
}
code, err := deploymentCode()
@@ -208,8 +248,13 @@ func (s *Server) handleCreateAuthorization(w http.ResponseWriter, r *http.Reques
}
result, err := tx.ExecContext(
r.Context(),
`INSERT INTO authorization_packages (authorization_id, package_id)
SELECT ?, id FROM packages WHERE id = ? AND enabled = TRUE`,
`INSERT INTO authorization_packages
(authorization_id, package_id, package_slug, display_name,
package_name, package_version, file_name, sha256)
SELECT ?, id, slug, display_name, package_name, package_version,
file_name, sha256
FROM packages
WHERE id = ? AND enabled = TRUE`,
authorizationID, packageID,
)
if err != nil {
@@ -222,6 +267,29 @@ func (s *Server) handleCreateAuthorization(w http.ResponseWriter, r *http.Reques
return
}
}
for _, actionSlug := range actionSlugs {
actionSlug = strings.TrimSpace(actionSlug)
if !validSlug(actionSlug) {
http.Error(w, "invalid installer action", http.StatusBadRequest)
return
}
result, err := tx.ExecContext(
r.Context(),
`INSERT INTO authorization_actions (authorization_id, action_slug)
SELECT ?, slug FROM installer_actions
WHERE slug = ? AND enabled = TRUE`,
authorizationID, actionSlug,
)
if err != nil {
http.Error(w, "unable to authorize installer action", http.StatusInternalServerError)
return
}
affected, _ := result.RowsAffected()
if affected != 1 {
http.Error(w, "selected installer action is unavailable", http.StatusBadRequest)
return
}
}
if err := tx.Commit(); err != nil {
http.Error(w, "unable to save authorization", http.StatusInternalServerError)
return
@@ -278,23 +346,18 @@ func (s *Server) handleUpsertPackage(w http.ResponseWriter, r *http.Request) {
return
}
}
if !validSlug(values["slug"]) || !validSHA256(values["sha256"]) {
http.Error(w, "invalid slug or SHA-256", http.StatusBadRequest)
if !validSlug(values["slug"]) ||
len(values["display_name"]) > 255 ||
!validRegistrySegment(values["package_name"], 255) ||
!validRegistrySegment(values["package_version"], 100) ||
!validRegistrySegment(values["file_name"], 255) ||
!validSHA256(values["sha256"]) {
http.Error(w, "invalid package metadata", http.StatusBadRequest)
return
}
enabled := r.FormValue("enabled") == "1"
_, err := s.db.ExecContext(
r.Context(),
`INSERT INTO packages
(slug, display_name, package_name, package_version, file_name, sha256, enabled)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
display_name = VALUES(display_name),
package_name = VALUES(package_name),
package_version = VALUES(package_version),
file_name = VALUES(file_name),
sha256 = VALUES(sha256),
enabled = VALUES(enabled)`,
err := s.savePackage(
r,
values["slug"],
values["display_name"],
values["package_name"],
@@ -312,6 +375,39 @@ func (s *Server) handleUpsertPackage(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/portal?notice=Package+saved", http.StatusSeeOther)
}
func (s *Server) savePackage(
r *http.Request,
slug string,
displayName string,
packageName string,
packageVersion string,
fileName string,
sha256 string,
enabled bool,
) error {
_, err := s.db.ExecContext(
r.Context(),
`INSERT INTO packages
(slug, display_name, package_name, package_version, file_name, sha256, enabled)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
display_name = VALUES(display_name),
package_name = VALUES(package_name),
package_version = VALUES(package_version),
file_name = VALUES(file_name),
sha256 = VALUES(sha256),
enabled = VALUES(enabled)`,
slug,
displayName,
packageName,
packageVersion,
fileName,
sha256,
enabled,
)
return err
}
func validSlug(value string) bool {
if value == "" || len(value) > 100 {
return false