post

package
v0.16.0-dev.c839379e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 19, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package post is the outbound engine behind nova-post: it renders one payload per channel deterministically, stores it under the drafts directory, and releases it only through the approve gate documented in docs/SPEC-OUTBOUND.md.

Nothing here reaches the network at draft time. A credential arrives only through the environment (nova-secrets exec), is read by name at send time, and is never printed, quoted or measured.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildDigest

func BuildDigest(date string, cairn, fleet []byte) []byte

BuildDigest renders the day's cairn beats and fleet numbers for email digest mode. It is deterministic in its three inputs and nothing else.

func CredentialName

func CredentialName(c Channel, target string) (string, error)

CredentialName is the environment variable a channel needs, by name only.

func EnsureDrafts

func EnsureDrafts(dir string) error

EnsureDrafts refuses a --drafts that is missing or is not a directory: the tool creates no directory and guesses none.

func ExitCode

func ExitCode(err error) int

ExitCode is the exit a caller owes an error: 2 for a refusal that does not name one, which is the "could not run" default.

func Refuse

func Refuse(reason, remedy string, exit int) error

Refuse builds a refusal.

func Render

func Render(c Channel, target, title, link, body string, at time.Time) ([]byte, error)

Render builds the exact payload bytes a channel leaves, once, by a fixed deterministic function. Those bytes are everything that can leave.

func RequireAllowlisted

func RequireAllowlisted(path string, c Channel, target string) error

RequireAllowlisted refuses a target the allowlist does not name. It is exit 1: the gate said NO, and no socket is opened before it passes.

func ScanBody

func ScanBody(body string) error

ScanBody refuses a body that names a secret, printing the line number and the shape, never the matched text.

Types

type Approval

type Approval struct {
	ID     string
	Sender string
	Hash   string
	Stamp  time.Time
}

Approval is the reading of one release receipt.

func ReadApproval

func ReadApproval(busDir, receiptID, wantHash string, now time.Time) (Approval, error)

ReadApproval finds the bus note named by receiptID and checks all four release rules, returning a refusal naming the one that failed. The clock is an argument so a test can stand at the edge of the 24-hour window without a --now flag: a caller who can name the time can forge freshness, so only code in a test ever chooses it.

type Channel

type Channel string

Channel is one of the four outward channels this tool speaks.

const (
	Ghost   Channel = "ghost"
	Bsky    Channel = "bsky"
	Email   Channel = "email"
	Discord Channel = "discord"
)

func ParseChannel

func ParseChannel(s string) (Channel, error)

ParseChannel validates the --channel value.

type DraftResult

type DraftResult struct {
	Hash    string
	Meta    Meta
	Payload []byte
}

DraftResult is what draft wrote.

func Draft

func Draft(o Options) (DraftResult, error)

Draft renders and stores one draft. It performs no network call: the allowlist gate is local and the body is scanned for secrets before anything is written.

type Mailer

type Mailer interface {
	Send(to string, payload []byte) error
}

Mailer delivers one email payload. It is an interface so tests can record the exact bytes without opening a socket.

type Meta

type Meta struct {
	Channel string `json:"channel"`
	Target  string `json:"target"`
	Title   string `json:"title"`
	Link    string `json:"link"`
	Created string `json:"created"`
	Bytes   int    `json:"bytes"`
}

Meta is the one-line sidecar written beside each payload.

type Options

type Options struct {
	Channel   Channel
	Target    string
	Draft     string
	Drafts    string
	Allowlist string
	Bus       string
	Approval  string
	File      string
	Title     string
	Link      string
	Digest    string
	Cairn     string
	Fleet     string
	Now       time.Time
	Transport Transport
}

Options is one verb's whole input. Every path comes from a flag.

type Refusal

type Refusal struct {
	Reason string
	Remedy string
	Exit   int
}

Refusal is a one-line refusal with its remedy and exit code: 2 when the invocation could not run, 1 when the gate or a provider said NO.

func (*Refusal) Error

func (r *Refusal) Error() string

type SendResult

type SendResult struct {
	Line string
}

SendResult is the one line send printed.

func Send

func Send(o Options) (SendResult, error)

Send releases a stored payload through the approve gate. The gate is checked before any socket is opened: a target outside the allowlist and an approval that is missing, for another hash, from another sender or stale are all refusals that make zero requests.

type ShowResult

type ShowResult struct {
	Payload []byte
	Meta    Meta
}

ShowResult is what show read.

func ReadDraft

func ReadDraft(drafts, hash string) (ShowResult, error)

ReadDraft loads a stored payload and its sidecar by hash.

func Show

func Show(drafts, hash string) (ShowResult, error)

Show reads the exact payload bytes a hash names.

type Transport

type Transport struct {
	HTTP      *http.Client
	GhostBase string
	BskyBase  string
	Mail      Mailer
}

Transport carries the seams a test replaces: the HTTP client, the per-channel base URLs, and the mailer. The zero value plus DefaultTransport is production.

func DefaultTransport

func DefaultTransport() Transport

DefaultTransport is the production transport.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL