Publish the reviewed security policy and evidence, exact runtime ABI enforcement, orphan-output and permission safeguards, dead-upstream cleanup, and the evidence-gated v1 launch plan. This commit is an exact sanitized export from the private development record. Material implementation and review were assisted by OpenAI Codex; Cole Speelman reviewed the changes and accepts human responsibility. Himesan-Output-Permission: v1.0 Signed-off-by: Cole Speelman <gamertan@noreply.localhost>
99 lines
3.1 KiB
Go
99 lines
3.1 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Package sando is the small production runtime for code generated by Hime-san.
|
|
// It contains rendering contracts and context-specific output helpers, but no
|
|
// router, HTTP server, middleware, or development tooling.
|
|
package sando
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"reflect"
|
|
)
|
|
|
|
// ABI identifies the generated-code contract implemented by this version of
|
|
// the runtime. It is descriptive metadata for people and tooling.
|
|
const ABI = "sando.v1"
|
|
|
|
// ABISandoV1 is the compile-time compatibility marker for generated code that
|
|
// requires the sando.v1 contract. A future runtime may retain this symbol while
|
|
// it remains backward compatible; an incompatible runtime must remove it so
|
|
// affected generated packages fail at build time instead of failing subtly at
|
|
// render time.
|
|
const ABISandoV1 = ABI
|
|
|
|
// RuntimeABI is a descriptive alias for ABI.
|
|
const RuntimeABI = ABI
|
|
|
|
var (
|
|
// ErrNilComponent is returned when Render is asked to render a nil
|
|
// component, including a typed nil held in a Component interface.
|
|
ErrNilComponent = errors.New("sando: nil component")
|
|
// ErrNilContext is returned when a component is rendered with a nil
|
|
// context.Context.
|
|
ErrNilContext = errors.New("sando: nil context")
|
|
// ErrNilWriter is returned when a component is rendered with a nil writer.
|
|
ErrNilWriter = errors.New("sando: nil writer")
|
|
)
|
|
|
|
// Component is the complete production rendering contract. Components are
|
|
// values rather than HTTP handlers so applications retain ownership of
|
|
// buffering, routing, headers, status codes, and error policy.
|
|
//
|
|
// A Component implemented by handwritten Go is a trusted output capability: it
|
|
// can write arbitrary bytes, block, panic, recurse, or change the surrounding
|
|
// HTML parser context. Hime-generated components are separately checked for a
|
|
// balanced, context-neutral HTML boundary before they implement this contract.
|
|
type Component interface {
|
|
Render(context.Context, io.Writer) error
|
|
}
|
|
|
|
// ComponentFunc adapts a function to Component.
|
|
type ComponentFunc func(context.Context, io.Writer) error
|
|
|
|
// Render calls f with ctx and w.
|
|
func (f ComponentFunc) Render(ctx context.Context, w io.Writer) error {
|
|
if f == nil {
|
|
return ErrNilComponent
|
|
}
|
|
if ctx == nil {
|
|
return ErrNilContext
|
|
}
|
|
if isNil(w) {
|
|
return ErrNilWriter
|
|
}
|
|
return f(ctx, w)
|
|
}
|
|
|
|
// Render renders component into w. It reports nil inputs as errors rather than
|
|
// panicking, including typed nil component and writer values.
|
|
func Render(ctx context.Context, w io.Writer, component Component) error {
|
|
if ctx == nil {
|
|
return ErrNilContext
|
|
}
|
|
if isNil(w) {
|
|
return ErrNilWriter
|
|
}
|
|
if isNil(component) {
|
|
return ErrNilComponent
|
|
}
|
|
return component.Render(ctx, w)
|
|
}
|
|
|
|
// isNil recognizes typed nil values stored in interfaces. It is intentionally
|
|
// confined to API boundary validation and is not a component registry.
|
|
func isNil(value any) bool {
|
|
if value == nil {
|
|
return true
|
|
}
|
|
|
|
rv := reflect.ValueOf(value)
|
|
switch rv.Kind() {
|
|
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
|
|
return rv.IsNil()
|
|
default:
|
|
return false
|
|
}
|
|
}
|