Files
gamertan 92a66db3df docs: publish Preview 19 dogfood evidence
Export the reviewed allowlisted snapshot from private source commit 05928cebd01b586cf9e9d4b8c8537a7605a6068c. This records the exact candidate, bounded capacity result, stateful migration scratch requirement, authenticated batch identity proof, and immediate live acceptance evidence.

AI-Assisted: OpenAI Codex
Signed-off-by: Cole Speelman <crspeelman@gmail.com>
2026-08-18 21:47:08 -04:00

592 lines
22 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-only
package httpserver
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"math"
"net/http"
"net/url"
"strconv"
"strings"
"unicode/utf8"
"gamertan.com/observatory/internal/identity"
"gamertan.com/observatory/internal/query"
"gamertan.com/observatory/internal/site"
"gamertan.com/observatory/internal/storage"
"gamertan.com/web/access"
"gamertan.com/web/auth"
"gamertan.com/web/authhttp"
)
func (s *Server) createSavedQuery(w http.ResponseWriter, r *http.Request) {
values, principal, ok := s.authorizeManagementForm(w, r, "organization_id", "csrf_token", "name", "description", "query")
if !ok {
return
}
s.saveQuery(w, r, values, principal, values.Get("query"))
}
func (s *Server) createBuiltQuery(w http.ResponseWriter, r *http.Request) {
required := []string{"organization_id", "csrf_token", "name", "description", "signal", "filter_operator", "window", "aggregate", "limit"}
optional := []string{"filter_field", "filter_value", "aggregate_field", "group_by", "bucket"}
values, principal, ok := s.authorizeManagementFormFields(w, r, required, optional)
if !ok {
return
}
text, err := buildAssistedQuery(values, s.options.MaxQueryRows)
if err != nil {
writeProblem(w, http.StatusUnprocessableEntity, "assisted query rejected")
return
}
s.saveQuery(w, r, values, principal, text)
}
func (s *Server) saveQuery(w http.ResponseWriter, r *http.Request, values url.Values, principal auth.Principal, text string) {
_, err := s.store.SaveQuery(r.Context(), storage.SavedQueryInput{
OrganizationID: values.Get("organization_id"), Name: values.Get("name"),
Description: values.Get("description"), Query: text,
ActorUserID: principal.User.ID, MaxRows: s.options.MaxQueryRows,
}, s.now())
if err != nil {
writeProblem(w, http.StatusUnprocessableEntity, "saved query rejected")
return
}
http.Redirect(w, r, "/app/?organization="+url.QueryEscape(values.Get("organization_id"))+"#saved-work", http.StatusSeeOther)
}
func buildAssistedQuery(values url.Values, maxRows int) (string, error) {
allowed := func(value string, candidates ...string) bool {
for _, candidate := range candidates {
if value == candidate {
return true
}
}
return false
}
signal := values.Get("signal")
if !allowed(signal, "logs", "metrics", "traces", "deployments") {
return "", fmt.Errorf("unsupported signal")
}
window := values.Get("window")
if !allowed(window, "15m", "1h", "6h", "24h", "168h") {
return "", fmt.Errorf("unsupported window")
}
limit, err := strconv.Atoi(values.Get("limit"))
if err != nil || limit < 1 || limit > maxRows || !allowed(values.Get("limit"), "10", "20", "50", "100", "250") {
return "", fmt.Errorf("unsupported limit")
}
stages := []string{signal}
filterField := values.Get("filter_field")
filterValue := values.Get("filter_value")
filterOperator := values.Get("filter_operator")
if !allowed(filterOperator, "==", "!=", ">=", "<=", ">", "<") {
return "", fmt.Errorf("invalid filter comparison")
}
if filterField == "" {
if filterValue != "" {
return "", fmt.Errorf("filter value requires a field")
}
} else {
if !allowed(filterField, "service", "project", "environment", "route", "status", "duration", "name", "severity", "value", "trace_id", "correlation_id") ||
filterValue == "" || len(filterValue) > 256 || !utf8.ValidString(filterValue) || strings.IndexByte(filterValue, 0) >= 0 {
return "", fmt.Errorf("invalid filter")
}
quoted := strconv.Quote(filterValue)
quoted = strings.ReplaceAll(quoted, "|", `\u007c`)
stages = append(stages, "where "+filterField+" "+filterOperator+" "+quoted)
}
stages = append(stages, "window "+window)
aggregate := values.Get("aggregate")
aggregateField := values.Get("aggregate_field")
groupBy := values.Get("group_by")
bucket := values.Get("bucket")
if aggregate == "none" {
if aggregateField != "" || groupBy != "" || bucket != "" {
return "", fmt.Errorf("summary options require an aggregate")
}
} else {
if !allowed(aggregate, "count", "min", "max", "sum", "avg", "p50", "p95", "p99") ||
!allowed(groupBy, "", "service", "project", "environment", "route", "status", "name", "severity") ||
!allowed(bucket, "", "1m", "5m", "15m", "1h") {
return "", fmt.Errorf("invalid summary")
}
expression := "count()"
if aggregate == "count" {
if aggregateField != "" {
return "", fmt.Errorf("count accepts no field")
}
} else {
if !allowed(aggregateField, "value", "duration", "status") {
return "", fmt.Errorf("numeric aggregate field required")
}
expression = aggregate + "(" + aggregateField + ")"
}
groups := make([]string, 0, 2)
if groupBy != "" {
groups = append(groups, groupBy)
}
if bucket != "" {
groups = append(groups, "window("+bucket+")")
}
stage := "summarize " + expression
if len(groups) > 0 {
stage += " by " + strings.Join(groups, ", ")
}
stages = append(stages, stage)
}
stages = append(stages, "limit "+strconv.Itoa(limit))
text := strings.Join(stages, " | ")
if _, err = query.Parse(text, maxRows); err != nil {
return "", err
}
return text, nil
}
func (s *Server) createDashboard(w http.ResponseWriter, r *http.Request) {
values, principal, ok := s.authorizeManagementForm(w, r, "organization_id", "csrf_token", "slug", "name", "description", "panel_title", "saved_query_id", "visualization")
if !ok {
return
}
organizationID := values.Get("organization_id")
queryValue, err := s.store.SavedQuery(r.Context(), organizationID, values.Get("saved_query_id"))
if err != nil {
writeProblem(w, http.StatusUnprocessableEntity, "dashboard query rejected")
return
}
visualization := values.Get("visualization")
if !validDashboardPresentation(queryValue, visualization) {
writeProblem(w, http.StatusUnprocessableEntity, "dashboard presentation does not match query")
return
}
_, err = s.store.SaveDashboard(r.Context(), storage.DashboardInput{
OrganizationID: organizationID, Slug: values.Get("slug"), Name: values.Get("name"),
Description: values.Get("description"), ActorUserID: principal.User.ID,
Panels: []storage.DashboardPanel{{Position: 0, Title: values.Get("panel_title"), Visualization: visualization, SavedQueryID: queryValue.ID}},
}, s.now())
if err != nil {
writeProblem(w, http.StatusUnprocessableEntity, "dashboard rejected")
return
}
http.Redirect(w, r, "/app/dashboards/"+url.PathEscape(values.Get("slug"))+"/?organization="+url.QueryEscape(organizationID), http.StatusSeeOther)
}
func (s *Server) updateDashboard(w http.ResponseWriter, r *http.Request) {
values, principal, ok := s.authorizeManagementForm(w, r, "organization_id", "csrf_token", "dashboard_id", "expected_revision", "slug", "name", "description")
if !ok {
return
}
current, ok := s.dashboardForRevision(w, r, values)
if !ok {
return
}
updated, err := s.store.SaveDashboard(r.Context(), storage.DashboardInput{
ID: current.ID, ExpectedRevision: current.Revision, OrganizationID: current.OrganizationID,
Slug: values.Get("slug"), Name: values.Get("name"), Description: values.Get("description"),
Panels: current.Panels, ActorUserID: principal.User.ID,
}, s.now())
if !writeDashboardRevisionResult(w, err) {
return
}
redirectDashboard(w, r, updated.Slug, current.OrganizationID)
}
func (s *Server) addDashboardPanel(w http.ResponseWriter, r *http.Request) {
values, principal, ok := s.authorizeManagementForm(w, r, "organization_id", "csrf_token", "dashboard_id", "expected_revision", "panel_title", "saved_query_id", "visualization")
if !ok {
return
}
current, ok := s.dashboardForRevision(w, r, values)
if !ok {
return
}
queryValue, err := s.store.SavedQuery(r.Context(), current.OrganizationID, values.Get("saved_query_id"))
if err != nil || !validDashboardPresentation(queryValue, values.Get("visualization")) {
writeProblem(w, http.StatusUnprocessableEntity, "dashboard panel rejected")
return
}
panels := append([]storage.DashboardPanel(nil), current.Panels...)
panels = append(panels, storage.DashboardPanel{Position: len(panels), Title: values.Get("panel_title"), Visualization: values.Get("visualization"), SavedQueryID: queryValue.ID})
updated, err := s.store.SaveDashboard(r.Context(), storage.DashboardInput{
ID: current.ID, ExpectedRevision: current.Revision, OrganizationID: current.OrganizationID,
Slug: current.Slug, Name: current.Name, Description: current.Description,
Panels: panels, ActorUserID: principal.User.ID,
}, s.now())
if !writeDashboardRevisionResult(w, err) {
return
}
redirectDashboard(w, r, updated.Slug, current.OrganizationID)
}
func (s *Server) updateDashboardPanel(w http.ResponseWriter, r *http.Request) {
values, principal, ok := s.authorizeManagementForm(w, r, "organization_id", "csrf_token", "dashboard_id", "expected_revision", "panel_title", "saved_query_id", "visualization")
if !ok {
return
}
current, ok := s.dashboardForRevision(w, r, values)
if !ok {
return
}
queryValue, err := s.store.SavedQuery(r.Context(), current.OrganizationID, values.Get("saved_query_id"))
if err != nil || !validDashboardPresentation(queryValue, values.Get("visualization")) {
writeProblem(w, http.StatusUnprocessableEntity, "dashboard panel rejected")
return
}
panelID := r.PathValue("panel")
panels := append([]storage.DashboardPanel(nil), current.Panels...)
found := false
for index := range panels {
if panels[index].ID != panelID {
continue
}
panels[index].Title = values.Get("panel_title")
panels[index].Visualization = values.Get("visualization")
panels[index].SavedQueryID = queryValue.ID
found = true
break
}
if !found {
writeProblem(w, http.StatusNotFound, "dashboard panel not found")
return
}
updated, err := s.store.SaveDashboard(r.Context(), storage.DashboardInput{
ID: current.ID, ExpectedRevision: current.Revision, OrganizationID: current.OrganizationID,
Slug: current.Slug, Name: current.Name, Description: current.Description,
Panels: panels, ActorUserID: principal.User.ID,
}, s.now())
if !writeDashboardRevisionResult(w, err) {
return
}
redirectDashboard(w, r, updated.Slug, current.OrganizationID)
}
func (s *Server) removeDashboardPanel(w http.ResponseWriter, r *http.Request) {
values, principal, ok := s.authorizeManagementForm(w, r, "organization_id", "csrf_token", "dashboard_id", "expected_revision")
if !ok {
return
}
current, ok := s.dashboardForRevision(w, r, values)
if !ok {
return
}
panelID := r.PathValue("panel")
panels := make([]storage.DashboardPanel, 0, len(current.Panels))
for _, panel := range current.Panels {
if panel.ID != panelID {
panel.Position = len(panels)
panels = append(panels, panel)
}
}
if len(panels) == len(current.Panels) {
writeProblem(w, http.StatusNotFound, "dashboard panel not found")
return
}
updated, err := s.store.SaveDashboard(r.Context(), storage.DashboardInput{
ID: current.ID, ExpectedRevision: current.Revision, OrganizationID: current.OrganizationID,
Slug: current.Slug, Name: current.Name, Description: current.Description,
Panels: panels, ActorUserID: principal.User.ID,
}, s.now())
if !writeDashboardRevisionResult(w, err) {
return
}
redirectDashboard(w, r, updated.Slug, current.OrganizationID)
}
func (s *Server) dashboardForRevision(w http.ResponseWriter, r *http.Request, values url.Values) (storage.Dashboard, bool) {
current, err := s.store.Dashboard(r.Context(), values.Get("organization_id"), r.PathValue("slug"))
if err != nil {
writeProblem(w, http.StatusNotFound, "dashboard not found")
return storage.Dashboard{}, false
}
revision, err := strconv.Atoi(values.Get("expected_revision"))
if err != nil || revision < 1 || values.Get("dashboard_id") != current.ID {
writeProblem(w, http.StatusBadRequest, "dashboard revision is invalid")
return storage.Dashboard{}, false
}
if revision != current.Revision {
writeProblem(w, http.StatusConflict, "dashboard changed; reload before editing")
return storage.Dashboard{}, false
}
return current, true
}
func validDashboardPresentation(saved storage.SavedQuery, visualization string) bool {
switch visualization {
case "table":
return true
case "stat":
return saved.AST.Summary != nil
case "timeseries":
return saved.AST.Summary != nil && saved.AST.Bucket > 0
default:
return false
}
}
func writeDashboardRevisionResult(w http.ResponseWriter, err error) bool {
if err == nil {
return true
}
if errors.Is(err, storage.ErrDashboardRevisionConflict) {
writeProblem(w, http.StatusConflict, "dashboard changed; reload before editing")
} else {
writeProblem(w, http.StatusUnprocessableEntity, "dashboard revision rejected")
}
return false
}
func redirectDashboard(w http.ResponseWriter, r *http.Request, slug, organizationID string) {
http.Redirect(w, r, "/app/dashboards/"+url.PathEscape(slug)+"/?organization="+url.QueryEscape(organizationID), http.StatusSeeOther)
}
func (s *Server) authorizeManagementForm(w http.ResponseWriter, r *http.Request, fields ...string) (url.Values, auth.Principal, bool) {
return s.authorizeManagementFormFields(w, r, fields, nil)
}
func (s *Server) authorizeManagementFormFields(w http.ResponseWriter, r *http.Request, required, optional []string) (url.Values, auth.Principal, bool) {
principal, ok := auth.PrincipalFromContext(r.Context())
values, err := readFormFields(w, r, 24<<10, required, optional)
token, sessionOK := authhttp.SessionToken(r, s.cookie)
csrfOK := err == nil && sessionOK && authhttp.VerifyCSRF(token, "dashboards:manage", values.Get("csrf_token"))
if !tokenBoundFormRequest(r, s.options.PublicOrigin, csrfOK) {
writeProblem(w, http.StatusForbidden, "valid dashboard form required")
return nil, auth.Principal{}, false
}
if !ok {
writeProblem(w, http.StatusUnauthorized, "authentication required")
return nil, auth.Principal{}, false
}
if err != nil {
writeProblem(w, http.StatusBadRequest, "invalid dashboard management request")
return nil, auth.Principal{}, false
}
organizationID := values.Get("organization_id")
scope := access.Scope{OrganizationID: organizationID}
if err = s.identity.ValidateResourceScope(r.Context(), scope); err != nil {
writeProblem(w, http.StatusBadRequest, "invalid organization")
return nil, auth.Principal{}, false
}
decision, err := s.identity.Access.Authorize(r.Context(), principal.User.ID, scope, identity.PermissionDashboardsManage)
if err != nil || !decision.Allowed {
writeProblem(w, http.StatusForbidden, "dashboard management denied")
return nil, auth.Principal{}, false
}
if !csrfOK {
writeProblem(w, http.StatusForbidden, "valid dashboard CSRF token required")
return nil, auth.Principal{}, false
}
return values, principal, true
}
func (s *Server) dashboard(w http.ResponseWriter, r *http.Request) {
organizationID, principal, ok := s.authorizeDashboardRead(w, r)
if !ok {
return
}
dashboard, err := s.store.Dashboard(r.Context(), organizationID, r.PathValue("slug"))
if err != nil {
writeProblem(w, http.StatusNotFound, "dashboard not found")
return
}
organizations, err := s.identity.OrganizationsForUser(r.Context(), principal.User.ID)
if err != nil {
writeProblem(w, http.StatusServiceUnavailable, "organization unavailable")
return
}
organizationName := "Organization"
for _, organization := range organizations {
if organization.ID == organizationID {
organizationName = organization.Name
break
}
}
view := site.DashboardView{
Head: s.head(dashboard.Name+" — Gamertan Observatory", dashboard.Description, "/app/dashboards/"+url.PathEscape(dashboard.Slug)+"/"),
DisplayName: principal.User.DisplayName, Organization: site.OrganizationOption{ID: organizationID, Name: organizationName, Selected: true},
ID: dashboard.ID, Slug: dashboard.Slug, Revision: dashboard.Revision,
Name: dashboard.Name, Description: dashboard.Description,
ExportURL: "/app/dashboards/" + url.PathEscape(dashboard.Slug) + "/export.json?organization=" + url.QueryEscape(organizationID),
}
manage, err := s.identity.Access.Authorize(r.Context(), principal.User.ID, access.Scope{OrganizationID: organizationID}, identity.PermissionDashboardsManage)
if err != nil {
writeProblem(w, http.StatusServiceUnavailable, "authorization unavailable")
return
}
view.CanManage = manage.Allowed
if view.CanManage {
token, sessionOK := authhttp.SessionToken(r, s.cookie)
if !sessionOK {
writeProblem(w, http.StatusUnauthorized, "authentication required")
return
}
view.ManageCSRF, err = authhttp.CSRFToken(token, "dashboards:manage")
if err != nil {
writeProblem(w, http.StatusServiceUnavailable, "session unavailable")
return
}
savedQueries, loadErr := s.store.SavedQueries(r.Context(), organizationID)
if loadErr != nil {
writeProblem(w, http.StatusServiceUnavailable, "saved queries unavailable")
return
}
for _, saved := range savedQueries {
view.SavedQueries = append(view.SavedQueries, site.SavedQuerySummary{ID: saved.ID, Name: saved.Name, Description: saved.Description, Query: saved.Query})
}
}
for _, panel := range dashboard.Panels {
view.Panels = append(view.Panels, s.dashboardPanel(r, principal.User.ID, organizationID, panel))
}
s.renderHTML(w, r, http.StatusOK, site.Dashboard(view))
}
func (s *Server) dashboardPanel(r *http.Request, userID, organizationID string, panel storage.DashboardPanel) site.PanelView {
view := site.PanelView{ID: panel.ID, SavedQueryID: panel.SavedQueryID, Title: panel.Title, Visualization: panel.Visualization, Table: site.TableView{Caption: panel.Title, Columns: []site.TableColumn{{Label: "Status"}}, Empty: "Panel data is unavailable."}}
saved, err := s.store.SavedQuery(r.Context(), organizationID, panel.SavedQueryID)
if err != nil {
return view
}
view.Query = saved.Query
scope := access.Scope{OrganizationID: organizationID, ProjectID: saved.Scope.ProjectID, EnvironmentID: saved.Scope.EnvironmentID, ServiceID: saved.Scope.ServiceID}
decision, err := s.identity.Access.Authorize(r.Context(), userID, scope, identity.PermissionTelemetryQuery)
if err != nil || !decision.Allowed || s.identity.ValidateResourceScope(r.Context(), scope) != nil {
return view
}
sensitive, err := s.identity.Access.Authorize(r.Context(), userID, scope, identity.PermissionTelemetryReadSensitive)
if err != nil {
return view
}
result, err := s.store.Query(r.Context(), saved.AST, query.Scope{OrganizationID: organizationID, ProjectID: saved.Scope.ProjectID, EnvironmentID: saved.Scope.EnvironmentID, ServiceID: saved.Scope.ServiceID, Sensitive: sensitive.Allowed}, s.options.QueryBudget, s.now())
if err != nil {
return view
}
view.Table = resultTable(panel.Title, result)
if panel.Visualization == "timeseries" {
view.Chart = resultChart(panel.Title, result)
}
if panel.Visualization == "stat" {
for _, row := range result.Rows {
for _, value := range row.Values {
if value != nil {
view.Stat = boundedCell(*value)
return view
}
}
}
}
return view
}
func resultChart(title string, result query.Result) site.ChartView {
if len(result.Columns) < 2 || len(result.Rows) == 0 {
return site.ChartView{}
}
valueIndex := len(result.Columns) - 1
valueType := result.Columns[valueIndex].Type
if valueType != "integer" && valueType != "float" && valueType != "duration" {
return site.ChartView{}
}
const maxPoints = 48
points := make([]struct {
label, display string
value float64
}, 0, min(len(result.Rows), maxPoints))
maximum := float64(0)
for index, row := range result.Rows {
if index >= maxPoints || valueIndex >= len(row.Values) || row.Values[valueIndex] == nil {
continue
}
value, err := strconv.ParseFloat(*row.Values[valueIndex], 64)
if err != nil || math.IsNaN(value) || math.IsInf(value, 0) || value < 0 {
return site.ChartView{}
}
labels := make([]string, 0, valueIndex)
for column := 0; column < valueIndex && column < len(row.Values); column++ {
if row.Values[column] != nil {
labels = append(labels, boundedCell(*row.Values[column]))
}
}
label := boundedCell(strings.Join(labels, " · "))
if label == "" {
label = fmt.Sprintf("Point %d", index+1)
}
display := boundedCell(*row.Values[valueIndex])
if unit := result.Columns[valueIndex].Unit; unit != "" {
display += " " + boundedCell(unit)
}
points = append(points, struct {
label, display string
value float64
}{label: label, display: display, value: value})
maximum = math.Max(maximum, value)
}
if len(points) == 0 {
return site.ChartView{}
}
if maximum == 0 {
maximum = 1
}
view := site.ChartView{Label: title + " visual summary"}
for _, point := range points {
view.Points = append(view.Points, site.ChartPoint{
Label: point.label, Value: strconv.FormatFloat(point.value, 'g', -1, 64),
Maximum: strconv.FormatFloat(maximum, 'g', -1, 64), Display: point.display,
})
}
return view
}
func (s *Server) exportDashboard(w http.ResponseWriter, r *http.Request) {
organizationID, _, ok := s.authorizeDashboardRead(w, r)
if !ok {
return
}
exported, err := s.store.ExportDashboard(r.Context(), organizationID, r.PathValue("slug"))
if err != nil {
writeProblem(w, http.StatusNotFound, "dashboard not found")
return
}
var body bytes.Buffer
encoder := json.NewEncoder(&body)
encoder.SetIndent("", " ")
if err = encoder.Encode(exported); err != nil {
writeProblem(w, http.StatusInternalServerError, "dashboard export unavailable")
return
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", "observatory-dashboard-"+r.PathValue("slug")+".json"))
w.Header().Set("Content-Length", fmt.Sprintf("%d", body.Len()))
if r.Method != http.MethodHead {
_, _ = w.Write(body.Bytes())
}
}
func (s *Server) authorizeDashboardRead(w http.ResponseWriter, r *http.Request) (string, auth.Principal, bool) {
principal, ok := auth.PrincipalFromContext(r.Context())
if !ok {
writeProblem(w, http.StatusUnauthorized, "authentication required")
return "", auth.Principal{}, false
}
values := r.URL.Query()
organizationID := values.Get("organization")
if len(values) != 1 || len(values["organization"]) != 1 || organizationID == "" {
writeProblem(w, http.StatusBadRequest, "organization is required")
return "", auth.Principal{}, false
}
scope := access.Scope{OrganizationID: organizationID}
if err := s.identity.ValidateResourceScope(r.Context(), scope); err != nil {
writeProblem(w, http.StatusBadRequest, "invalid organization")
return "", auth.Principal{}, false
}
decision, err := s.identity.Access.Authorize(r.Context(), principal.User.ID, scope, identity.PermissionDashboardsRead)
if err != nil || !decision.Allowed {
writeProblem(w, http.StatusForbidden, "dashboard access denied")
return "", auth.Principal{}, false
}
return organizationID, principal, true
}