Updates to all six top-level docs to describe the new flow:
- Storage: HTML tools live in website/releases/ as committed static
files. Per-version files are real bytes; partial-version pins and
channel mirrors are checked-in symlinks. No manifest.json, no Codeberg
indirection, no Caddy regex-rewrite.
- URL scheme: <tool>_v<X.Y.Z>.html (exact), <tool>_v<X.Y>.html (latest
patch), <tool>_v<X>.html (latest minor), <tool>_<channel>.html
(channel mirror). All resolve via the symlink chain.
- Cascade rule: stable cut → beta + alpha symlinks reset to stable;
beta cut → alpha resets to beta. Channels are never stale.
- No -alpha.N / -beta.N counter tags. Channel URLs are stable URLs by
design; counters defeat that. The on-page <date> · <sha> label is
enough for traceability.
- bootstrap/install.sh is the canonical install path. The four hand-
rolled snippets are gone; one script handles all three deployment
patterns + both target shapes.
- Helm charts under helm/ (zddc-server-{prod,dev}/) build from source
via init container; documented as the recommended k8s deployment
path.
- zddc-server now publishes binaries on stable cuts only — no alpha/
beta channel for binaries. Active dev runs through the dev helm chart
which builds from source on each rollout.
Files updated:
- CLAUDE.md — Repo shape, Most-used commands, Things that bite if you
forget. Drops mentions of manifest.json, the Codeberg-as-canonical
model, and -alpha.N/-beta.N tags.
- AGENTS.md — website/ tree, Releasing — channels and layout, Channel
discipline rules (renumbered to add coordinated minor/major bump
rule), Freshen helper, Bootstrap stubs, zddc-server Release tagging.
- ARCHITECTURE.md — website/ tree, build.sh step 5, Channels section,
level-2 bootstrap description.
- README.md — tool publishing description, link to helm/.
- bootstrap/README.md — install path is install.sh now; pin URL table
uses static symlinks; CORS check uses release-asset URLs (not
manifest.json).
- zddc/README.md — Quick Start uses Codeberg URLs directly (no proxy);
Release tagging is stable-only; Distribution / Versioning sections
rewritten.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rolls back the HTML-tool side of the Codeberg-as-canonical refactor
(commits 2dc9ad2, b28c4ae, bdac8dc) in favor of a simpler model:
per-version HTML files committed under website/releases/ as immutable
real files; partial-version pins (<tool>_v<X.Y>.html, <tool>_v<X>.html)
and channel mirrors (<tool>_<channel>.html) are checked-in symlinks.
Docker-tag pattern: :1.2.3 is pinned, :1.2 floats, :1 floats further,
:stable floats furthest.
URL scheme — every URL resolves to actual HTML via the symlink chain;
no JS indirection, no manifest.json, no Caddy regex-rewrite:
/releases/<tool>_v<X.Y.Z>.html exact version (real file)
/releases/<tool>_v<X.Y>.html latest patch within X.Y.* (symlink)
/releases/<tool>_v<X>.html latest within X.*.* (symlink)
/releases/<tool>_stable.html current stable (symlink)
/releases/<tool>_beta.html current beta (symlink to stable when no
active beta; real file when beta is in flight)
/releases/<tool>_alpha.html current alpha (similar — symlink to beta
or stable when no active alpha)
Cascade rule (in shared/build-lib.sh promote_release):
--release [version] (stable cut) → write per-version file; refresh 5
symlinks (_v<X.Y>, _v<X>, _stable,
_beta, _alpha) → new versioned file;
tag <tool>-v<X.Y.Z>.
--release beta → overwrite <tool>_beta.html with real
bytes; cascade _alpha.html → _beta.html
(symlink). No tag — channel URLs are
stable URLs by design; counters defeat
that.
--release alpha → overwrite <tool>_alpha.html with real
bytes. No tag, no other side-effects.
Plain `sh tool/build.sh` → dist/ only. No website/releases/
side-effect, no commit.
Code changes:
- .gitignore — drop website/releases/*.html and website/releases/zddc-server-*
exclusions; HTML tool files are tracked again. Replace the comment with
the new model description.
- shared/build-lib.sh — drop next_prerelease (no -alpha.N / -beta.N counter
tags). Drop the Codeberg-upload path for HTML tools (no longer sourcing
publish-codeberg-release.sh from build-lib). promote_release rewritten
with two helpers: _promote_stable (per-version file + 5 symlinks + tag)
and _promote_channel (overwrite mirror + cascade alpha→beta on beta cut).
- zddc/release.sh — drop alpha/beta channel path entirely; binaries publish
only on stable cuts. zddc-server's beta/alpha builds-from-source via the
helm charts (next phase) — no binary distribution needed for those channels.
- bootstrap/level2.html.tmpl — drop manifest.json fetch; resolve ?v= to a
static URL via the symlink chain. New suffixFor() handles channel names,
exact versions, and partial-version pins (?v=0.0, ?v=0). Same logic in
level1.html.tmpl already works because the local-staging files (e.g.
../<tool>_v0.0.html) exist via the same symlink scheme.
- build.sh build_releases_index — revert to filesystem scan of
website/releases/ instead of Codeberg API call. Drop manifest.json
generation. Per-tool sections list channel chips + per-version pin links;
zddc-server section links to Codeberg release pages directly.
- tests/build-label.spec.js — fix the channel-label regex to match the
pre-release-semver format introduced in commit 9459139 ("v0.0.3-alpha · ...").
Pre-existing test failure that wasn't caught at the time.
Storage:
- 30 new committed files under website/releases/ — 10 real (per-version) +
20 symlinks (5 tools × 4 partial/channel variants, plus alpha as a real
file by default).
- Initial state: stable v0.0.2 across all 5 tools; alpha/beta/v0.0/v0
symlinks all point at <tool>_v0.0.2.html.
- manifest.json deleted (no longer needed).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 2dc9ad2 commit ("refactor: distribute via Codeberg release assets,
drop the upstream image") rewrote AGENTS.md and CLAUDE.md but left
several pre-existing references to the old write-to-website/releases
flow and the now-removed Containerfile / podman-compose / release-image.sh.
This sweeps the rest:
- CLAUDE.md
- drop "podman/podman-compose" from the zddc/ blurb (no Containerfile)
- drop the broken `podman build -t zddc-server zddc/` command
- rewrite the "Most-used commands" table so --release semantics match
actual behavior (tag + Codeberg upload, not file write)
- rewrite "Things that bite": replace "never write to website/releases/"
and the obsolete "alpha exception" bullet with the new rules
($CODEBERG_TOKEN required, dist files no longer force-tracked, etc.)
- rewrite the website/ description in "Repo shape" to reflect that
only index.html + manifest.json live there now
- ARCHITECTURE.md
- rewrite the website/ directory tree (no more <tool>_v*.html, _stable
symlinks, or _alpha/_beta files)
- rewrite "Channels" section: every cut now tags + uploads to Codeberg,
alpha/beta have .N counters and matching tags, no more in-place
overwrites
- rewrite the build-label table: dev builds carry the next-stable
target as a -alpha pre-release suffix with full timestamp + dirty
marker (was: "Built: <ts> BETA")
- update level-2 bootstrap description: resolves channel via
manifest.json, fetches /releases/<tag>/<asset>, not a flat URL
- update landing-tool description: ships only as Codeberg release
asset, not a committed website/releases/landing_v<X>.html
- AGENTS.md
- update website/ tree to the post-refactor layout
- replace the two-step podman build / podman-compose run blocks under
zddc-server with a Go build + go run quickstart (no container in
this repo)
- drop the "Containerfile uses a multi-stage build" note from the
"Notes" list (Containerfile is gone)
- drop the stale "landing/build.sh writes website/index.html" note —
website/index.html is now hand-edited, not produced by landing's
build
- README.md (top-level)
- tools table no longer links to /releases/<tool>_stable.html
(those URLs return 404 post-refactor); link to the releases page
once instead
- bootstrap/README.md
- update the "permanent pin" URL examples and CORS verification
snippet to use /releases/<tag>/<asset> URLs (Caddy → Codeberg)
instead of the old flat /releases/<tool>_<channel>.html pattern
- explain that channel resolution is via manifest.json now
- zddc/README.md
- rewrite Quick Start: download a release binary or build from source,
no `podman build`
- rewrite TLS examples to invoke ./zddc-server directly instead of
`podman run ... zddc-server` (image name no longer exists)
- mention ZDDC_INSECURE_DIRECT in the env-var table and the plain-HTTP
example — startup is refused without it on non-loopback binds
- replace the "Container image" section with "Distribution" (binaries
on Codeberg, no image) and the "Building" section with go build
instructions
- replace "Release Tagging" with documentation of zddc/release.sh
(the canonical replacement for release-image.sh, which is gone)
- shared/build-lib.sh
- fix the comment claiming "plain builds mirror to website/releases/"
— they don't anymore
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the codeberg.org/varasys/zddc-server registry image, which had
no remaining consumer outside this shop. The two chart Dockerfiles
(tnd-zddc-chart) now compile zddc-server from source at build time,
fetching the right tag from a Codeberg release. release-image.sh,
zddc/Containerfile, and zddc/podman-compose.yaml are gone.
Build artifacts (HTML tools + zddc-server binaries) move from
website/releases/ in this repo to Codeberg release assets attached to
git tags. The website at zddc.varasys.io serves them by reverse-
proxying /releases/<tag>/<asset> to the corresponding Codeberg URL,
so consumers (zddc-use, level-2 bootstrap stubs, the chart
Dockerfiles) only ever talk to zddc.varasys.io.
Releases page becomes server-rendered static HTML regenerated on each
build via a single Codeberg API call. A small website/releases/manifest.json
maps <tool>-<channel> → tag for runtime channel resolution by zddc-use
and the level-2 stubs.
Files added:
- shared/publish-codeberg-release.sh — POSIX-sh helper that creates a
Codeberg release for a tag (sets prerelease flag from tag suffix)
and uploads/replaces release assets idempotently. Sourced by
build-lib.sh and zddc/release.sh.
- zddc/release.sh — replaces release-image.sh. Tags + cross-compiles
binaries via native Go (no podman needed; install Go) + uploads to
Codeberg release assets. No image build, no registry push.
Files modified:
- shared/build-lib.sh — promote_release tags + uploads via the helper
for stable AND alpha/beta now (alpha/beta were untagged before).
update_alpha removed; per-tool build.sh files no longer mirror to
website/releases/<tool>_alpha.html on plain dev builds.
- build.sh — prefers native go build over the old podman-based
cross-compile (which is gone with Containerfile). build_releases_index
queries the Codeberg API once and writes static HTML + manifest.json,
with graceful fallback when the API is unreachable.
- bootstrap/level2.html.tmpl — fetches manifest.json to resolve
channel → tag, then fetches the asset from /releases/<tag>/<asset>
(Caddy proxy). Replaces the old /releases/<tool>_<channel>.html flat
URL pattern. Operators with curl'd level-2 stubs need to re-issue
them — this is a breaking change.
- AGENTS.md, CLAUDE.md — rewritten to describe the new flow.
- .gitignore — releases/ artifacts now expected to be on Codeberg, not
committed locally.
NOT in this commit (deferred until $CODEBERG_TOKEN is provisioned):
- Backfilling existing tags as Codeberg releases.
- Cleanup commit: git rm-ing the existing artifacts in website/releases/.
Until backfill happens, those files are how operators with old
bootstrap stubs still get content. Once Codeberg has the assets,
drop them.
- The Caddy reverse-proxy config on zddc.varasys.io.
Operator-side changes (not in this repo):
- tnd-zddc-chart Dockerfile.prod and Dockerfile (dev) need updating
to compile from source rather than `FROM codeberg.org/...:stable`.
Done in a separate commit on that repo.
- Caddyfile rule for the /releases/<tag>/<asset> reverse-proxy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the super-admin-only /.admin/ surface with a public-by-default
/.profile/ page that layers admin tools server-side based on the
caller's effective access:
- Universal (everyone, anonymous included): identity card, effective
access summary, theme picker, localStorage utilities (export / import
/ clear, landing-presets viewer).
- Subtree admins additionally see: editable .zddc files list (linking
to the existing form-based editor) and a "Create new project folder"
form.
- Super-admins additionally see: server config, log viewer, whoami
headers (the old /.admin/ JSON endpoints, repointed under /.profile/).
Project creation is gated on CanEditZddc(newDir) — the same strict-
ancestor rule that already governs .zddc writes — so no new authority
concept is introduced. ValidateProjectName mirrors the existing
reserved-prefix policy (no leading '.' or '_', no path separators).
/.admin/* is hard-cut: no redirect shim. Old URLs fall through to the
existing dot-prefix guard and 404. Custom CSS file rename: prefer
<root>/.profile.css, fall back to legacy <root>/.admin.css.
Per-resource 404 leakage gates preserved on whoami / config / logs /
zddc / projects so non-admin callers cannot detect the existence of
admin-only sub-resources.
Tree-wide gofmt -w applied as a side-effect.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "Install on your server" section of the home page now prints four
short shell snippets — copy-paste into a terminal, files land in CWD.
Each uses curl to fetch the relevant bootstrap files; nothing else to
install:
1. Self-contained: fetches the 5 current-stable tool HTMLs into CWD
plus a _template/ directory of level-1 stubs.
~1.8 MB on disk; no runtime dependency on the
site after install.
2. Track stable: fetches 5 tiny level-2 stubs (~10 KB total)
that fetch zddc.varasys.io's stable channel
on every page load.
3. Track beta: same, for beta.
4. Track alpha: same, for alpha.
Each snippet card explains when/why to use that option directly inline.
Implementation:
- build.sh now produces website/bootstrap/level1/<tool>.html and
website/bootstrap/track-{alpha,beta,stable}/<tool>.html as
standalone files (rather than packaging them into zips).
- install.zip and track-{alpha,beta,stable}.zip are removed; the
snippets curl the per-channel stubs directly.
- Docs updated: README, ARCHITECTURE, CLAUDE, AGENTS, bootstrap/README,
zddc/README, landing/build.sh comment.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generalize the admin model from "single root super-admin" to a
delegated chain: a `<dir>/.zddc/admins` list grants admin authority
for that subtree, with a strict-ancestor rule preventing
self-elevation (you cannot edit the .zddc that grants your own
authority — only files strictly below it).
Add a guided server-rendered editor at /.admin/zddc/edit?path=<dir>
so subtree admins can manage their fiefdoms without filesystem
access. JSON API at /.admin/zddc covers GET (file + effective chain
+ can_edit), POST (atomic write + cache invalidation), DELETE,
plus a /tree endpoint listing every .zddc visible to the caller.
Optional theming via <root>/.admin.css.
Validation: glob syntax check, root-self-demotion rejection,
reserved-prefix path guard, YAML round-trip sanity. Writes are
atomic (temp file + fsync + rename) and invalidate the policy
cache.
Also includes the prior in-flight `Title` field on ProjectInfo
so per-project .zddc titles surface on the landing-page picker.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds tini to the runtime image and routes ENTRYPOINT through it so
zddc-server runs as PID 2 with proper orphan reaping and signal
forwarding. Today zddc-server is a single-process server and the change
is invisible; the motivation is the upcoming render path that will
shell out to pandoc (which itself shells out to xelatex / lua filters /
dot) — any grandchild orphaned by a mid-run crash gets reparented to
PID 1, and a Go server is not the right thing to put in charge of
reaping subprocesses it never spawned.
tini is ~24KB and does exactly this one job. Putting it in the upstream
image (rather than each downstream consumer's Dockerfile) means every
deployment of codeberg.org/varasys/zddc-server gets the fix for free,
including the Burns & McDonnell prod chart wrapper that's about to land.
Cut a new release with `sh release-image.sh <version> stable` to
publish.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The .archive virtual directory now emits both <tracking>.html (highest
base rev) and <tracking>_<rev>.html (each specific base rev) so HTML
documents can deep-link to a known revision and have it resolve to the
first chronologically received copy. Modifier files (<rev>+C1 etc.) stay
reachable via the resolver but aren't surfaced in the listing.
.archive at any folder depth serves the same global index — the depth
exists so offline HTML can use ../.archive/<tracking>.html and let the
browser resolve it before the request reaches the server. The earlier
attempt at scoping listings to the contextPath subtree was wrong; gating
is purely by ACL: contextPath gates the listing endpoint, and each
entry's resolved file gets its own per-target ACL check (404 on denial,
not 403, so cross-subtree existence isn't disclosed).
Adds the first tests for the previously untested archive package, plus
end-to-end ACL coverage for the handler (cascade direction, default-deny
once any .zddc exists, anonymous denied under allow:[\"*@…\"], stable
Location across contextPaths).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- release-image.sh now defaults to alpha (was stable). Active dev no
longer silently advances :stable; that tag only moves on a deliberate
`sh release-image.sh <ver> stable`. Same cascade logic, reordered
default. Updated AGENTS.md and zddc/README.md sections accordingly.
- zddc/Containerfile: dropped the "see .woodpecker.yml" comment since
that file no longer exists; pointed the docs to release-image.sh.
- build.sh: dropped the "CI builds the runtime container directly"
parenthetical; the cross-compiled host-binaries build is the only
thing that step actually produces.
Why alpha as the default: caught it during active development —
:stable kept advancing every release because the script defaulted
there. Solo workflow + alpha default = `:stable` is a deliberate
gesture, not a side-effect.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes .woodpecker.yml and replaces the tag-triggered image publish flow
with a local-build-and-push script (release-image.sh).
Why: the CI added two indirections (Woodpecker dashboard, Codeberg secrets
config) that aren't worth the cost for a single-developer release flow.
When the previous release didn't show up in the package registry, "did
the release happen?" required checking three places (the git tag, the
CI dashboard, the registry); with local builds, success or failure is
visible in the developer's terminal immediately.
The cascade behavior is preserved: `sh release-image.sh 0.0.3` publishes
:0.0.3 :stable :beta :alpha just like the .woodpecker.yml job did. Beta
and alpha channels work identically (`sh release-image.sh 0.0.3-beta.1
beta` → :0.0.3-beta.1 :beta :alpha).
The git-tag convention stays (`zddc-server-vX.Y.Z`); now you tag *and*
run the script as two coordinated steps. AGENTS.md "Release tagging" and
zddc/README.md "Release Tagging" / "Container image" updated to reflect
the new flow. No code change in the binary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ACLMiddleware now slog.Debug's the configured email-header name, the
observed value at that name, and the full r.Header map on every request.
Off at the default INFO log level; enable per-pod with ZDDC_LOG_LEVEL=debug.
Motivated by debugging the X-Auth-Request-Email passthrough chain — when
access logs show email=anonymous, /.admin/whoami is unreachable (the
admin gate requires a non-empty email, which is the chicken-and-egg).
The debug log line dumps headers without the gate, so an operator can
identify whichever header name the upstream proxy is actually setting
(X-Forwarded-User, X-Forwarded-Email, Remote-User, X-Authentik-Email,
etc.) and adjust ZDDC_EMAIL_HEADER accordingly.
The debug-level dump captures auth tokens and cookies along with
everything else; safe in dev clusters, not appropriate for production
unless the operator is comfortable with the trade-off. README documents
the trade-off in the Admin Debug Page section.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Block style (one '- entry' per line) is recommended for hand-edited config
in this repo: cleaner diffs, easier to comment per-entry, no surprise YAML
quoting traps. The Admin Debug Page example mixed admins (block) with
acl.allow (flow); flip allow to block too for consistency.
Inline-in-table flow-style examples (lines 143-145) stay flow — block
style would mangle the cell layout — and that's a fine exception when the
list lives inside a one-cell context.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Listings now filter both '.' and '_' prefixes:
- '.' entries: excluded from listings AND 404 on direct HTTP access
(existing behavior). For invisible side-state like .devshell.
- '_' entries: excluded from listings only — direct URL access still
works. For operator scaffolding like install.zip's _template/
directory of bootstrap stubs that should be reachable but should
not appear in the project picker.
Filter applied at both listing entry points: ServeProjectList (the
project picker JSON at GET / Accept: application/json) and the generic
listing/FromDirEntries (used by ServeDirectory for sub-directory
browse listings).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three improvements bundled because they all ship as zddc-server v0.0.2:
* /.admin/ debug dashboard with /whoami, /config, /logs sub-routes.
Authorization via a top-level `admins:` glob list in <ZDDC_ROOT>/.zddc
(root-only — subdir entries deliberately ignored to prevent privilege
escalation via subtree write access). Non-admin requests get 404 so the
page is invisible. Recent logs surface via a 500-entry slog ring buffer
teed off the existing TextHandler. Lets operators debug without
kubectl exec.
* Default ZDDC_EMAIL_HEADER changes from `X-Email` to
`X-Auth-Request-Email` — the oauth2-proxy / nginx auth-request
convention that the TND helm chart already sets explicitly.
Operators who set the env var explicitly are unaffected; deployments
relying on the previous default need to set ZDDC_EMAIL_HEADER=X-Email
or update their proxy.
* dispatch() rejects any URL whose segments contain a dot prefix other
than the recognized virtual prefixes (.admin, cfg.IndexPath /
.archive). Matches the existing listing-pipeline filter so hidden
subtrees on the served PVC (e.g. /srv/.devshell — used by the
in-cluster dev-shell for persistent home-dir state) become
unreachable via direct HTTP fetch, not just hidden in listings.
Refreshes the X-Email reference in website/index.html accordingly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The renamed channel naming (latest → stable) only landed in the
filesystem layout and the bootstrap; the image-publish pipeline still
applied :latest as an alias for :stable on stable releases. Drop it
to avoid mixed terminology.
.woodpecker.yml: stable releases now apply only :X.Y.Z, :stable,
:beta, :alpha. zddc/README.md updated to show stable/beta/alpha
channel tags and explicitly note :latest is not published.
To clean up the existing :latest tag on the registry (one-time):
curl -X DELETE \
-H "Authorization: token $CODEBERG_TOKEN" \
https://codeberg.org/api/v1/packages/varasys/container/zddc-server/latest
or via the web UI at codeberg.org/VARASYS/-/packages/container/zddc-server.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 'latest' label for the current-stable channel was inconsistent
with the channel set we use elsewhere (alpha / beta / stable). Rename
to 'stable' so URLs, file names, zip names, and image tags all line
up with the channel terminology used in the bootstrap, AGENTS.md
discipline rules, and chart consumers.
File / artifact renames
- website/releases/<tool>_latest.html → <tool>_stable.html (5 files)
- website/track-latest.zip → track-stable.zip
- shared/build-lib.sh: promote_release writes/refreshes _stable.html
- bootstrap/level{1,2}.html.tmpl: channels map drops 'latest', keeps
'stable' as the canonical name. ?v=stable is now the explicit way
to switch to current-stable for one request (alongside ?v=alpha,
?v=beta, and ?v=X.Y.Z).
- build.sh: install.zip sources from <tool>_stable.html; emits
track-stable.zip instead of track-latest.zip.
Container image (.woodpecker.yml rewritten)
- Tag publishing now cascades:
zddc-server-vX.Y.Z → :X.Y.Z, :stable, :beta, :alpha, :latest
zddc-server-vX.Y.Z-beta.N → :X.Y.Z-beta.N, :beta, :alpha
zddc-server-vX.Y.Z-alpha.N → :X.Y.Z-alpha.N, :alpha
- :stable, :beta, :alpha are now first-class channel pointers; chart
consumers (e.g. tnd-zddc-chart) can FROM :beta for dev and FROM
:stable for prod.
- :latest kept as an alias for :stable per Docker convention.
Documentation sweep
- AGENTS.md, ARCHITECTURE.md, CLAUDE.md, README.md
- bootstrap/README.md, zddc/README.md
- website/index.html, website/zddc-server.html
- transmittal/template.html, transmittal/README.md
all updated to reference _stable.html / track-stable.zip / the
'stable' channel name. ARCHITECTURE.md's manual freshen example
points at ./freshen-channel instead of the old git-checkout snippet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Batch 1 of the chart-vs-project split. The project now ships a
hardened runtime image as part of every zddc-server release; downstream
deployments (e.g. the Burns & McDonnell Helm chart) will FROM this
image instead of cloning and building from source.
zddc/Containerfile (target: server)
- Tag the runtime stage `server` so `podman build --target server`
is unambiguous (the existing `binaries` target still works).
- Bake the bundled landing + archive tool HTML at /opt/zddc-server/web.
Useful for self-contained demos (`ZDDC_ROOT=/opt/zddc-server/web`)
and as a fallback web root when no external mount is supplied.
- Set fixed UID/GID 1000 for the non-root zddc user so volume
permissions are predictable across hosts.
- Add ENV ZDDC_ROOT=/srv default so a `podman run -v data:/srv` works
with no further config; explicit ZDDC_ROOT overrides.
- Declare VOLUME /srv to make the data-mount expectation explicit.
- Add OCI image labels (title, description, source, documentation,
license, vendor).
- Install ca-certificates so any future outbound HTTPS works.
- Add a HEALTHCHECK for `docker run` users (Kubernetes overrides).
build.sh
- Make the cross-platform podman binary build conditional on `podman`
being present. CI doesn't need it (the runtime container image's
own builder stage produces linux/amd64 internally), but having
build.sh sh-only-runnable means CI doesn't have to do nested
containers just to assemble dist/web.
- Reorder so `zddc/dist/web/` is assembled before the binary build
(allows the binary build to be skipped without breaking the bundle).
.woodpecker.yml (new)
- Triggers on tag push matching `zddc-server-v*`.
- Step 1 (alpine + sh): runs `sh build.sh` to assemble dist/web,
computes the image tag (`${TAG#zddc-server-v}` plus `latest`).
- Step 2 (docker-buildx plugin): builds and publishes
codeberg.org/varasys/zddc-server:{X.Y.Z, latest}. Auth via the
codeberg_user / codeberg_token Woodpecker secrets — these need
one-time setup in repo Settings; documented in zddc/README.md.
zddc/README.md
- New "Container image" section: pull URL, image properties (alpine,
non-root UID 1000, EXPOSE 8443, VOLUME /srv, baked web bundle),
example `podman run` invocation.
- New "Env-var contract (for chart consumers)" table: the variables
Helm charts and Compose files should set explicitly when running
behind a TLS-terminating reverse proxy with SSO. This is the
documented interface between project and downstream charts.
- "Release Tagging" section now points at .woodpecker.yml and lists
the two Woodpecker secrets that must be configured.
Validated locally:
podman build --target server -t zddc-server-test .
podman run -e ZDDC_ROOT=/opt/zddc-server/web -e ZDDC_TLS_CERT=none \
-e ZDDC_INSECURE_DIRECT=1 -e ZDDC_ADDR=:8080 \
-p 18080:8080 zddc-server-test
curl http://localhost:18080/ → HTTP 200, bundled landing tool.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ZDDC — Zero Day Document Control. A file-naming convention plus five
single-file HTML tools (archive, transmittal, classifier, mdedit,
landing) and an optional Go HTTP server (zddc-server) with ACL and a
virtual archive index. Self-contained, offline-capable, dependency-free.
See README.md for an overview, AGENTS.md and ARCHITECTURE.md for the
build/release/architecture detail, bootstrap/README.md for the
two-level deployment install pattern, and zddc/README.md for the
HTTP server.