bd7a11d4e7
Extract the verbatim-duplicated helpers into shared homes: - buildEnv -> plugin.BuildWorkloadEnv (base plugin pkg; a sourceName param preserves each plugin's slog prefix / log-scraper text) - idShort -> plugin.IDShort - commitStatusReporter -> staticsite.CommitStatusReporter, re-parameterized on primitives (owner/repo/sha/targetURL/enabled) so staticsite needs no dependency on the plugin package; reporter tests ported to staticsite (plus a new nil-provider case) containerNameFor/imageTagFor are intentionally left per-plugin: their prefixes differ (dw-site- vs tf-build-) and name real Docker resources, so merging them would risk mis-routing. Behavior-preserving; the static/dockerfile test suites pass unchanged. Reviewed: go APPROVE (0 CRITICAL/HIGH).
67 lines
2.2 KiB
Go
67 lines
2.2 KiB
Go
package static
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/alexei/tinyforge/internal/workload/plugin"
|
|
)
|
|
|
|
// containerNameFor is the deterministic container name. Includes
|
|
// w.Name for visual continuity in `docker ps` plus the ID short for
|
|
// uniqueness.
|
|
func containerNameFor(w plugin.Workload) string {
|
|
return fmt.Sprintf("dw-site-%s-%s", w.Name, plugin.IDShort(w))
|
|
}
|
|
|
|
// imageTagFor is the deterministic image tag — same shape as the
|
|
// container name so the linkage between an image and the workload
|
|
// that owns it stays obvious from `docker images`.
|
|
func imageTagFor(w plugin.Workload) string {
|
|
return fmt.Sprintf("dw-site-%s-%s:latest", w.Name, plugin.IDShort(w))
|
|
}
|
|
|
|
// siteVolumeKey is the input to docker.SiteVolumeName / EnsureSiteVolume
|
|
// / RemoveSiteVolume. Composing it here (instead of building the full
|
|
// name ourselves) keeps the naming concern in one place — those docker
|
|
// helpers wrap the value with their own `tinyforge-site-...-data`
|
|
// envelope. Including idShort prevents two workloads sharing a name
|
|
// from sharing one persistent volume.
|
|
func siteVolumeKey(w plugin.Workload) string {
|
|
return fmt.Sprintf("%s-%s", w.Name, plugin.IDShort(w))
|
|
}
|
|
|
|
// sanitizeError clamps an error string so persisting it (in
|
|
// containers.extra_json's last_error) or echoing it (via the
|
|
// outbound notification webhook) cannot leak a multi-line response
|
|
// body, an HTTP header echoing the access token, or a stack trace.
|
|
//
|
|
// Strategy:
|
|
// - Reduce to a single line (replace any newline / tab with space).
|
|
// - Cap to a short maxLen so a very long Gitea/GitHub error body
|
|
// never round-trips into operator-visible state.
|
|
// - Redact the access token verbatim if it appears in the message
|
|
// (defense in depth — providers shouldn't echo tokens but a
|
|
// misbehaving one could).
|
|
func sanitizeError(msg, accessToken string) string {
|
|
if msg == "" {
|
|
return ""
|
|
}
|
|
if accessToken != "" {
|
|
msg = strings.ReplaceAll(msg, accessToken, "[REDACTED]")
|
|
}
|
|
// Collapse whitespace runs onto one line.
|
|
msg = strings.Map(func(r rune) rune {
|
|
switch r {
|
|
case '\n', '\r', '\t':
|
|
return ' '
|
|
}
|
|
return r
|
|
}, msg)
|
|
const maxLen = 240
|
|
if len(msg) > maxLen {
|
|
msg = msg[:maxLen] + "…"
|
|
}
|
|
return msg
|
|
}
|