feat: publish Gamertan Tend preview source

Sanitized root snapshot from private source commit a72903c63e1753f9e6ffbf40453c0830bdfc05c5 and tree 295641e67eef5979da76746d8ae271249568263e. Private development history and workflows are excluded by the exact allowlist.

AI-assisted: OpenAI Codex helped implement, test, and audit this preview.
Signed-off-by: Cole Speelman <crspeelman@gmail.com>
This commit is contained in:
2026-08-14 14:01:02 -04:00
commit b68fa2487d
46 changed files with 4067 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
# Architecture
Tend has three deliberately separate boundaries.
## Package boundary
`tend package` accepts only a clean checkout whose `HEAD` exactly matches the
configured pushed branch. It rejects Go module replacements and unversioned
dependencies, builds the configured main package twice with `GOWORK=off`, and
requires byte-identical output. The resulting archive contains only:
- the service binary;
- `RELEASE.json`;
- `BUILDINFO.json`;
- `SBOM.spdx.json`; and
- `SHA256SUMS`.
The external archive digest is the release identity used by deployment.
## Target-host boundary
`tend deploy` runs on the Linux target. Transfer and SSH authentication stay
outside Tend v0.1; application-local transfer commands move the artifact and
the identical Tend binary to a root-controlled staging directory. Tend then
requires the expected digest to be repeated as a separately approved digest.
Dry-run validation extracts into a temporary directory and does not touch the
release tree. Activation acquires the shared lock, installs a content-addressed
release, verifies all embedded checksums and manifest fields, and starts the
candidate without evaluating configuration as shell code.
## Activation boundary
Blue/green mode points the inactive slot at the new release, restarts and
probes it, atomically replaces one imported Caddy handler, validates the full
Caddy configuration, reloads Caddy, and records the prior active slot.
Singleton mode starts the new release in a hardened transient systemd unit on a
separate loopback address, probes it, stops the candidate, changes the current
release pointer, and restarts the installed singleton unit.
Any failure before state persistence restores the previously observed Caddy
bytes and/or release pointers. Rollback is a separate explicit command over the
recorded state. It rechecks health and readiness, but deliberately does not
apply the current release's content markers to an older release whose routes
may differ. Pruning preserves both active and previous releases.
+73
View File
@@ -0,0 +1,73 @@
# Preview dogfood evidence
This is maintainer-run operational evidence, not an independent audit or a
general reliability claim. It records the acceptance campaign completed on
August 14, 2026 before Tend's first public preview.
## Assessed candidate
- Source commit: `306d085e518cb4fe7b20a66d1e2ceb171e54ebdc`.
- Linux/amd64 candidate binary SHA-256:
`a9d53e286317d5acad9c0c321dc8d6240efee1e992714a892aba5be7c190dffc`.
- Candidate archive SHA-256:
`52639d16cd55b1dfe7c4ce63d4523676a6e8fe7cf57ef25787938c4070f49bd3`.
- Toolchain: Go 1.26.6, `CGO_ENABLED=0`, `-trimpath`.
- Two fresh packages from the clean pushed commit were byte-identical.
- Tests, race tests, vet, license checks, public-snapshot isolation, and
`govulncheck v1.1.4` passed. The vulnerability scan reported no known
reachable vulnerabilities with the August 14, 2026 database.
- Trusted Gitea verification completed successfully for the exact commit.
The release tag and attached assets must still identify their own exact source
commit and digests. Any code change after this campaign requires the dogfood
sequence to be repeated.
## Sandwich Hime website
The singleton-candidate strategy packaged and activated website preview 25:
- application source commit:
`0429e3f0160aa4fd4d262bc5857bc232c2149cb8`;
- artifact SHA-256:
`25025a05bb1aa6689f5f0779064b24a7c8193ff93c1395a2b3bd342588c3926a`;
- application toolchain: Go 1.26.6;
- isolated transient candidate passed health, readiness, and application
smoke checks before the singleton pointer changed;
- explicit rollback returned to preview 24, and the exact approved preview 25
artifact was then reactivated;
- canonical, documentation, news, `llms.txt`, and Gamertan-mounted routes
returned HTTP 200 after reactivation.
## Gamertan
The blue-green strategy packaged and activated Gamertan preview 8:
- application source commit:
`3acfa6a8e66ca3827c840d1fe9bc0b51c69c0a45`;
- artifact SHA-256:
`76db7a9a6c496c204f653dc5e42c935272159320cc344b6a4db6374535c696ad`;
- application toolchain: Go 1.26.6;
- the inactive slot passed health, readiness, and page-marker checks before a
validated atomic Caddy handler replacement;
- the handler retained `root:caddy` ownership, mode `0640`, and Sandwich Hime
routing precedence;
- explicit rollback restored preview 7, and the exact approved preview 8
artifact was then reactivated;
- homepage, project pages, news, feed, discovery files, the Sandwich Hime
mount, and EQL Helper continuity returned HTTP 200 after reactivation.
## Finding resolved during the campaign
An earlier rollback attempt stopped safely before changing traffic because it
applied the new release's content markers to an older release whose route set
was different. Tend now uses the full configured smoke suite for new
deployments and health/readiness checks for an already-recorded rollback
target. A regression test requires that separation. The fixed candidate then
completed both live rollback sequences.
## Boundaries
The campaign covered one Linux/systemd/Caddy host and two small Go services.
It did not cover databases, migrations, containers, Kubernetes, hostile root,
or EQL Helper's application-specific catalog activation. Artifact transport
remains an application-owned, host-key-verified step outside Tend v0.1.
+14
View File
@@ -0,0 +1,14 @@
# Public snapshot boundary
Private development happens in `gamertan/tend-dev`. The canonical public
repository is not a mirror of that Git history. `scripts/export-public.sh`
creates an exact-file, exact-commit, allowlisted filesystem snapshot and records
its source commit and tree in `PUBLIC-SNAPSHOT.json`.
The exporter refuses dirty or unpushed source, destinations inside the source
or Git metadata, workflow directories, non-allowlisted paths, and known private
material markers. The resulting directory receives a new public root commit.
Public Gitea is canonical for issues, contributions, and releases. GitHub is a
read-only discovery copy of the same public tree. Tags belong only to canonical
Gitea.
+39
View File
@@ -0,0 +1,39 @@
# Threat model
## Protected properties
- A release is identified by an operator-approved SHA-256 digest.
- Only regular, bounded, allowlisted archive entries are extracted.
- Release roots, state, pointers, and Caddy files reject symlink substitution
at their checked boundaries.
- Configuration is strict JSON and is never interpolated into a shell command.
- Candidate health is established before traffic or the singleton current
pointer changes. New deployments also satisfy configured content smoke
checks; rollback uses health and readiness because future-release content
markers are not valid requirements for an older retained release.
- Caddy configuration validates before reload.
- An activation failure restores the previously observed state.
- Active and previous releases survive pruning.
## Trusted inputs
Reviewed source, the Go toolchain, root-owned `tend.json`, systemd unit files,
the Caddy handler template, the operator, and the target host's root account are
trusted. Packaging a hostile repository can execute hostile Go compiler hooks
or consume resources; Tend is not a source-code sandbox.
## Adversarial inputs
Artifact paths and bytes, archive metadata, stale or malformed state, HTTP
responses, subprocess failures, and filesystem objects at managed paths are
validated and fail closed. Process output is bounded.
## Non-goals and preview limits
Tend does not defend against a concurrently malicious root user, a compromised
kernel/toolchain/systemd/Caddy installation, denial of service by the trusted
application, or secrets already exposed through service configuration. v0.1
does not manage data migrations, databases, containers, Kubernetes, or
application-specific activation. Transfer remains an application-local,
reviewed step until a transport can be added without weakening host-key and
credential boundaries.