feat: publish Tend v0.2 preview source

Publish the reviewed allowlisted snapshot whose exact binary completed maintenance deployment, rollback, and reactivation exercises for Gamertan and Sandwich Hime.

Private-Source-Commit: 4d7094c8b7c61991bfb67b11fc1558724c874eb2

Private-Source-Tree: 54a2f74804f7acddf3755d7d4da5b97f5fc28381

AI-Assistance: OpenAI Codex assisted implementation, testing, security review, and release verification.
Signed-off-by: Cole Speelman <crspeelman@gmail.com>
This commit is contained in:
2026-08-16 19:02:08 -04:00
parent b2cc4482f6
commit 00d1dd4209
47 changed files with 1590 additions and 124 deletions
+17 -6
View File
@@ -3,17 +3,28 @@
This subtree is licensed 0BSD so an operator can copy and adapt it without
bringing the Tend program's AGPL license into an application configuration.
The blue/green example expects separately reviewed environment files:
The blue/green example expects one separately reviewed environment file that
the two installed slots and transient validation use consistently:
```text
# /etc/example-site/blue.env
EXAMPLE_LISTEN=127.0.0.1:8090
# /etc/example-site/green.env
EXAMPLE_LISTEN=127.0.0.1:8091
# /etc/tend/environment/example-site.env
APP_SECRET=replace-on-server
```
The blue/green systemd slot units then read the nonsecret listen address from
`/etc/tend/slots/example-site-blue.env` or `-green.env`; Tend overrides only
the isolated candidate address. Secret values never enter `tend.json`.
The singleton example follows the same split: its shared root-only environment
file omits the configured listen key, the installed unit owns the live address,
and Tend supplies only the transient candidate address. This prevents a shared
environment file from overriding the isolated candidate port.
Production configuration belongs outside the source checkout, owned by root,
and not group- or world-writable. The Caddy handler template is an entire
imported handler fragment; the enclosing site, matchers, and routing precedence
remain operator-owned.
`server/` demonstrates the schema-2 receive policy, forced OpenSSH command,
restricted sudo entry, two independent service configurations, and secret-file
placement. The values are placeholders, not an installation script.
+2 -1
View File
@@ -6,7 +6,8 @@ After=network.target
Type=simple
DynamicUser=yes
ExecStart=/opt/example-site/slots/%i/example-site
EnvironmentFile=/etc/example-site/%i.env
EnvironmentFile=/etc/tend/environment/example-site.env
EnvironmentFile=/etc/tend/slots/example-site-%i.env
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
+4 -3
View File
@@ -1,16 +1,17 @@
{
"schema_version": 1,
"service": { "name": "example-site", "allowed_host": "example.test" },
"schema_version": 2,
"service": { "name": "example-site", "allowed_host": "example.test", "environment_file": "/etc/tend/environment/example-site.env" },
"build": { "package": "./cmd/site", "binary": "example-site", "branch": "main" },
"deployment": {
"strategy": "blue_green",
"root": "/opt/example-site",
"lock_file": "/run/lock/gamertan-deploy.lock",
"lock_file": "/run/lock/tend-deploy.lock",
"state_file": "/opt/example-site/tend-state.json",
"health_path": "/healthz",
"readiness_path": "/readyz",
"candidate_timeout_seconds": 30,
"smoke": [{ "path": "/", "contains": "Example site" }],
"public_smoke": [{ "url": "https://example.test/", "contains": "Example site" }],
"blue_green": {
"caddy_config": "/etc/caddy/Caddyfile",
"caddy_handler": "/etc/caddy/example-site-handler.caddy",
+3
View File
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: 0BSD
APP_MODE=development
APP_SECRET=replace-with-a-local-random-value
+2
View File
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: 0BSD
restrict,command="sudo -n /usr/local/bin/tend receive --policy /etc/tend/receive-policy.json" ssh-ed25519 REPLACE_WITH_DEPLOY_KEY tend-deploy
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: 0BSD
DOCS_LISTEN=127.0.0.1:8102
APP_SECRET=replace-on-server
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: 0BSD
APP_SECRET=replace-on-server
+19
View File
@@ -0,0 +1,19 @@
# SPDX-License-Identifier: 0BSD
[Unit]
Description=Example singleton site
After=network.target
[Service]
Type=simple
DynamicUser=yes
ExecStart=/opt/example-site/current/example-site
EnvironmentFile=/etc/tend/environment/example-site.env
Environment=EXAMPLE_LISTEN=127.0.0.1:8092
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
Restart=on-failure
[Install]
WantedBy=multi-user.target
+16
View File
@@ -0,0 +1,16 @@
{
"schema_version": 1,
"config_root": "/etc/tend/services",
"incoming_root": "/var/lib/tend/incoming",
"shared_lock_file": "/run/lock/tend-deploy.lock",
"services": {
"docs-site": {
"config": "/etc/tend/services/docs-site.json",
"max_artifact_bytes": 134217728
},
"example-site": {
"config": "/etc/tend/services/example-site.json",
"max_artifact_bytes": 134217728
}
}
}
+24
View File
@@ -0,0 +1,24 @@
{
"schema_version": 2,
"service": { "name": "docs-site", "allowed_host": "docs.example.test", "environment_file": "/etc/tend/environment/docs-site.env" },
"build": { "package": "./cmd/docs", "binary": "docs-site", "branch": "main" },
"deployment": {
"strategy": "singleton_candidate",
"root": "/opt/docs-site",
"lock_file": "/run/lock/tend-deploy.lock",
"state_file": "/opt/docs-site/tend-state.json",
"health_path": "/healthz",
"readiness_path": "/readyz",
"candidate_timeout_seconds": 30,
"smoke": [{ "path": "/", "contains": "Documentation" }],
"public_smoke": [{ "url": "https://docs.example.test/", "contains": "Documentation" }],
"singleton": {
"unit": "docs-site.service",
"address": "127.0.0.1:8102",
"candidate_address": "127.0.0.1:18102",
"listen_env": "DOCS_LISTEN",
"current_link": "/opt/docs-site/current",
"previous_link": "/opt/docs-site/previous"
}
}
}
@@ -0,0 +1,24 @@
{
"schema_version": 2,
"service": { "name": "example-site", "allowed_host": "example.test", "environment_file": "/etc/tend/environment/example-site.env" },
"build": { "package": "./cmd/site", "binary": "example-site", "branch": "main" },
"deployment": {
"strategy": "singleton_candidate",
"root": "/opt/example-site",
"lock_file": "/run/lock/tend-deploy.lock",
"state_file": "/opt/example-site/tend-state.json",
"health_path": "/healthz",
"readiness_path": "/readyz",
"candidate_timeout_seconds": 30,
"smoke": [{ "path": "/", "contains": "Example site" }],
"public_smoke": [{ "url": "https://example.test/", "contains": "Example site" }],
"singleton": {
"unit": "example-site.service",
"address": "127.0.0.1:8092",
"candidate_address": "127.0.0.1:18092",
"listen_env": "EXAMPLE_LISTEN",
"current_link": "/opt/example-site/current",
"previous_link": "/opt/example-site/previous"
}
}
}
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: 0BSD
EXAMPLE_LISTEN=127.0.0.1:8090
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: 0BSD
EXAMPLE_LISTEN=127.0.0.1:8091
+3
View File
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: 0BSD
Defaults:tend-deploy env_keep += "SSH_ORIGINAL_COMMAND"
tend-deploy ALL=(root) NOPASSWD: /usr/local/bin/tend receive --policy /etc/tend/receive-policy.json
+4 -4
View File
@@ -1,22 +1,22 @@
{
"schema_version": 1,
"service": { "name": "example-site", "allowed_host": "example.test" },
"schema_version": 2,
"service": { "name": "example-site", "allowed_host": "example.test", "environment_file": "/etc/tend/environment/example-site.env" },
"build": { "package": "./cmd/site", "binary": "example-site", "branch": "main" },
"deployment": {
"strategy": "singleton_candidate",
"root": "/opt/example-site",
"lock_file": "/run/lock/gamertan-deploy.lock",
"lock_file": "/run/lock/tend-deploy.lock",
"state_file": "/opt/example-site/tend-state.json",
"health_path": "/healthz",
"readiness_path": "/readyz",
"candidate_timeout_seconds": 30,
"smoke": [{ "path": "/", "contains": "Example site" }],
"public_smoke": [{ "url": "https://example.test/", "contains": "Example site" }],
"singleton": {
"unit": "example-site.service",
"address": "127.0.0.1:8092",
"candidate_address": "127.0.0.1:18092",
"listen_env": "EXAMPLE_LISTEN",
"environment": {},
"current_link": "/opt/example-site/current",
"previous_link": "/opt/example-site/previous"
}