Commit graph

20 commits

Author SHA1 Message Date
5c33c8a821 docs: ACL/security overhaul (cascade rules, OPA, caching)
Three docs aligned with the preceding three feature commits.

zddc/README.md
--------------
Major overhaul of the access-control narrative. The previous "three-
tier" example table was misleading: it claimed a project-level
allow-list "restricts" access under a parent wildcard, when actually
the cascade is additive (a non-team employee falls up to root and
matches *@company.com). Operators reading the old docs would build
deployments that looked locked-down but leaked across the company.

New sections under "Access control: the .zddc cascade":
  * Step 1: starter .zddc — leads with the public-by-default warning
    and the --insecure escape hatch
  * How a request is evaluated — bottom-up walk with code citations
  * Glob patterns — @-boundary rule
  * When the cascade helps and when it fights you — the asymmetry
    between adding strangers (easy) and excluding insiders (hard)
  * Pick your layout — decision matrix for common shapes
  * Worked example: paired open/closed projects + third-party archive
    — full layout with trace table for two representative users
  * Patterns that look secure but aren't — anti-patterns including
    same-level allow+deny shadow, leaf-allow-doesn't-restrict,
    apps:-as-UI-mount
  * Trust model and invariants — auth boundary, subtree authority,
    root-only escalation gate
  * Trust boundary — network isolation requirement, anonymous
    information disclosure on /, audit-log integrity
  * Debugging permissions — manual cascade trace
  * Directory visibility / Reserved hidden segments
  * How to verify in 5 minutes — recipe with negative anti-pattern test
  * Federal-readiness gap analysis — bulleted with NIST control refs
  * External policy decider — OPA wire format, deployment shapes,
    failure modes
  * OPA decision cache — TTL semantics, knobs
  * Reference Rego policy — --print-rego, parity test rationale
  * Caching and ETags — content-hash story, why not server-side
  * Future work

Plus env-var table updates for ZDDC_INSECURE, ZDDC_OPA_URL,
ZDDC_OPA_FAIL_OPEN, ZDDC_OPA_CACHE_TTL; CORS narrative reflects
default-empty.

ARCHITECTURE.md
---------------
New "Server security model" section between Form Renderer and CSS:
cooperating layers (auth / policy decider / cascade / tool-rooted
view / reserved prefixes / audit log), commercial-vs-federal trust
model side-by-side, why the tool-rooted view matters for third-party
containment.

AGENTS.md
---------
Two new env-var rows (ZDDC_OPA_URL, ZDDC_OPA_CACHE_TTL); ACL line
sharpened with cascade rules + cross-reference; ZDDC_CORS_ORIGIN
description updated for default-empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 17:46:57 -05:00
ae758550a8 docs: surface recent server features in README + AGENTS
zddc/README.md and AGENTS.md hadn't caught up with the loading-
efficiency + ops-hygiene work. Add coverage for:

- ETag + max-age=0 on embedded tool HTMLs (304 on revalidation)
- gzip compression middleware (75% size reduction on bodies > 1 KB)
- public landing page semantics (root bypasses dir-level ACL;
  per-project filtering still hides hidden projects)
- file-based audit log (default-on, auto-mkdir, hostname-tagged
  filename + record field, lumberjack-rotated)
- HTTP timeouts (slowloris-resistant)

Adds ZDDC_ACCESS_LOG row to both env-var tables.
2026-05-04 07:49:17 -05:00
7570fb7494 refactor: separate website repo + deploy-host model
Migrates from in-repo orphan `website` branch + LFS to a two-repo +
deploy-host model so source editing is fully decoupled from live state.

  - Source code stays here (codeberg.org/VARASYS/ZDDC).
  - Hand-edited website content moves to a separate Codeberg repo
    (codeberg.org/VARASYS/ZDDC-website, cloned at ~/src/zddc-website/).
  - Live site is /srv/zddc/ on the deploy host (Caddy bind-mount),
    populated by ./deploy from this repo's dist/release-output/ plus
    ~/src/zddc-website/.
  - Releases are no longer in any git history — reproducible from
    <tool>-vX.Y.Z tags via `./build release X.Y.Z`. No LFS, no
    Codeberg release assets.

Build/deploy split:
  - ./build (no arg) is source-only; nothing in dist/release-output/
    or /srv/zddc/ is touched.
  - ./build alpha|beta|release seeds dist/release-output/ from
    /srv/zddc/releases/ (preserving symlinks), then mutates the
    channel(s) being cut on top. The bundle is always a complete
    intended-live snapshot, so the verifier sees a complete world
    and ./deploy --releases (rsync --delete-after) replaces live
    state cleanly.
  - New ./deploy wraps the rsync flow with --content / --releases
    subcommands.

Docs updated to reflect the new model: CLAUDE.md, AGENTS.md,
ARCHITECTURE.md, zddc/README.md, README.md, .gitignore, shared/
build-lib.sh comments, deprecated zddc/release.sh message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 09:14:40 -05:00
6167e99f3a chore: simplify CLI to ./build / ./build beta / ./build release
Renames build.sh → build and replaces the --release flag form with
subcommands:

  ./build                  cut alpha (default; active dev iteration)
  ./build beta             cut beta  (cascades alpha → beta)
  ./build release          cut stable (coordinated next version)
  ./build release X.Y.Z    cut stable at explicit version
  ./build help

The contract shift: there's no longer a "plain dev build that doesn't
touch channels" at the top level. Every full-stack build is a publish
action — running ./build IS active dev iteration, which is what alpha
already meant. To iterate on one tool without writing to the website
worktree, use the per-tool sh tool/build.sh (unchanged).

Output continues to land in ${ZDDC_DEPLOY_RELEASES_DIR:-$HOME/src/zddc-website/releases}
and nothing is pushed automatically. Commit + push the website branch
yourself when you want to publish. Stable cuts still tag locally on
main; tags push separately too.

Behind the scenes: the export of ZDDC_DEPLOY_RELEASES_DIR is moved
above the per-tool build.sh invocations so children inherit it. The
prior "if RELEASE_CHANNEL else write_zddc_server_stubs_all" branch is
collapsed since RELEASE_CHANNEL is always set under the new CLI.

Docs (CLAUDE.md, AGENTS.md, ARCHITECTURE.md, zddc/README.md) updated
to reference ./build everywhere; the per-tool sh tool/build.sh refs
stay (they're a separate, narrower entry point).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:11:10 -05:00
6cc0d2ae27 feat(zddc-server): /.auth/admin forward_auth endpoint
A machine-only HTTP endpoint that returns 200 if the request's
X-Auth-Request-Email is in the root .zddc admins: list, 403 otherwise.
No body, no redirect — pure authorization decision intended to be
polled by an upstream proxy's forward_auth directive.

The motivating use case is gating /devshell/* (code-server) in the
dev-shell pod on root-admin status before the request ever reaches
code-server, which has no built-in ACL of its own. zddc-server's
own routes keep the existing .zddc cascade ACL and don't go through
this endpoint.

Reuses zddc.IsAdmin (one cached map lookup) so the check is cheap
enough to call on every request. Edits to /srv/.zddc propagate via
the existing fsnotify watcher's policy-cache invalidation.

Tests cover empty email, non-admin, admin, and the bootstrap state
where no root .zddc exists (deny everyone — the safe default).

Docs: zddc/README.md "Forward-auth target for upstream proxies"
section + AGENTS.md notes bullet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 21:08:39 -05:00
9fce18cd45 feat: lockstep release infra + cascade/.archive fixes + profile perf + page redesign
Four entangled change-sets from one session, committed together because
their file-level overlap (build.sh, docs, embedded/, watcher.go, …) makes
post-hoc separation noisy:

* fix(archive): nested-party + folder-type cascade
  transmittalIsUnderVisibleParty short-circuited on the first matched
  party segment, only checking the immediately-next segment for a
  folder-type marker. Paths like BM/sub/Issued/<txn> bypassed the Issued
  toggle entirely. Replaced with isUnderHiddenFolderType (full-path) +
  any-segment party match. Eight new Playwright cases pin the contract
  in tests/archive-cascade.spec.js.

* refactor(zddc-server): scope .archive index by project
  archive.Index now buckets by top-level segment
  (.ByProject[<project>].ByTracking[<tracking>]). Resolve and AllEntries
  take a project parameter; handler extracts it from contextPath's first
  segment. /.archive/ at root returns 404 — stable refs must be
  project-rooted. Within-project (tracking, rev) collisions emit a WARN
  with both paths. Cross-project tracking-number duplicates no longer
  collide.

* perf(zddc-server): lazy-load expensive bits of the profile page
  serveProfilePage now ships a minimal shell: Email, EmailHeader,
  IsSuperAdmin (root .zddc only). Visible projects + admin subtrees +
  editable scaffolds populate client-side via /.profile/access. Subtree-
  admin scaffolds live in <template id="tmpl-subtree-admin">; pure
  non-admins receive no live admin form. ScanZddcFiles now memoized,
  invalidated on .zddc events by the watcher and writer helpers.

* feat: lockstep release + redesigned releases page
  sh build.sh --release [version|alpha|beta] is the canonical lockstep
  cut: every tool (5 HTML + zddc-server) bumps to the same coordinated
  version. zddc-server binaries now committed under website/releases/
  with the same cascade chain as HTML tools (no more Codeberg release-
  asset publication). zddc/release.sh deprecated (kept as a guard);
  shared/publish-codeberg-release.sh removed.

  Releases page redesigned as an action-first install guide: hero +
  version dropdown that rewires every download link, channel chips for
  always-visible alpha/beta access (state-aware labels: "tracks stable"
  vs "active dev"), Path A (zddc-server with platform auto-detect from
  UA), Path B (5 standalone tool HTMLs), version-pinning empowerment
  narrative (drop-a-copy vs .zddc apps: cascade), channels explainer.

  Channel-link verifier asserts every <tool>_{stable,beta,alpha}.html
  resolves at the end of every build. Bootstrap-friendly: zddc-server
  artifact checks skip until the first lockstep cut anchors the chain.

Tests: 167 Playwright + all Go packages green.
Docs: CLAUDE.md, AGENTS.md, ARCHITECTURE.md, zddc/README.md updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:11:38 -05:00
adb6904397 docs: rewrite for embedded + cascade install model
Updates every repo doc to reflect the simplified install model:

  - Local install is just a download from /releases/.
  - Server install is just running zddc-server (current-stable HTMLs
    embedded at compile time).
  - Customize via .zddc apps: cascade entries (channel/version/URL/path,
    with default + per-app composition); editor at /.profile/zddc/.

Removes references to the old install scripts, level-1/level-2 stubs,
admin UI at /.profile/apps, SHA-256 verification, TOFU writes, refresh
worker, and ZDDC_APPS_* env vars.

zddc/README.md: replaces "Landing Page and Tool Install" section with
"Apps: virtual tool HTMLs" — covers the folder-name availability rules,
the resolution chain (real-file override / cascade / embedded), spec
syntax cheat sheet, cache layout under <ZDDC_ROOT>/_app/, the ?v=
cache-only override, and the X-ZDDC-Source response header.

ARCHITECTURE.md: install-distribution-model section rewritten to
describe the embed-first / cascade-override model with one canonical
example.

AGENTS.md, CLAUDE.md: short-form summaries pointing at the same model.

README.md: install bullet rewritten.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 15:25:57 -05:00
7365e94cac docs: align with simplified release model
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>
2026-04-30 09:56:34 -05:00
bdac8dc4fb docs: clean up drift left over from the Codeberg release-assets refactor
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>
2026-04-30 08:01:20 -05:00
916e53d873 feat(install): replace .zip downloads with copy-paste shell snippets
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>
2026-04-29 13:30:32 -05:00
40d9956e54 chore(release): default to alpha cascade; tidy stale CI references
- 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>
2026-04-28 18:17:16 -05:00
5960fbca91 chore(release): drop Woodpecker CI; release-image.sh is now canonical
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>
2026-04-28 18:07:27 -05:00
15ccf554d2 feat(zddc-server): debug-level dump of every request's full headers
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>
2026-04-28 17:53:55 -05:00
83cd5a6bbc docs(zddc-server): normalize .zddc YAML examples to block-style lists
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>
2026-04-28 17:39:20 -05:00
89c5ec064d feat(zddc-server): hide _-prefixed entries from listings (e.g. _template)
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>
2026-04-28 16:56:47 -05:00
9ef90800b1 feat(zddc-server): admin debug page + X-Auth-Request-Email default + hidden-segment guard
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>
2026-04-28 14:02:06 -05:00
c2e8d364a9 chore(ci): drop :latest image tag — stable/beta/alpha is canonical
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>
2026-04-28 10:07:52 -05:00
67f794e6d0 refactor: rename channel 'latest' to 'stable' across all artifacts
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>
2026-04-28 09:30:24 -05:00
cc35f7179b feat(zddc-server): publishable runtime image + Codeberg CI pipeline
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>
2026-04-27 14:46:59 -05:00
ea385b5366 Initial commit
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.
2026-04-27 11:05:47 -05:00