docs: canonical folder layout, role-based ACL, WORM, lazy creation
Update reference.html § 9 (transmittal workflow): replace the legacy
per-party tree (project/{party-name}/{incoming,received,issued}) with
the current canonical layout — project root has working/, staging/,
reviewing/, archive/, and per-party folders sit under
archive/<party>/{mdl,incoming,received,issued}/. Note lazy creation,
case-fold matching, the per-user virtual <viewer-email>/ entry, mdl
opening the table editor, and the staging↔working drafting mirror.
Add a "Drafting a response transmittal" subsection describing how
inbound submittals (-SUB- @ IFR/IFA) flow through staging→working
into archive/<party>/issued/ as RS* responses.
Update index.html "Access control via .zddc files" bullet to describe
what the server actually does today: cascade direction, the five
verbs (r/w/c/d/a), explicit deny via empty grant, and the
X-Auth-Request-Email convention. Add new bullets for roles (with a
short YAML example), WORM archive folders + drop-in producer pattern,
lazy folder creation + case-fold matching, the cascade tracer
admin endpoint, and an expanded OPA paragraph (input shape, cache
TTL, fail-open flag, --print-rego=federal). Update the install card's
tool-folder list to use lowercase canonical names, mention browse,
and add mdl.table.html as the per-party MDL view.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e4149bf8cd
commit
f81fb4e769
2 changed files with 64 additions and 14 deletions
26
index.html
26
index.html
|
|
@ -175,9 +175,21 @@
|
||||||
<p style="margin-top: var(--spacing-md);"><strong><code class="inline">zddc-server</code></strong> is a small Go binary purpose-built to serve ZDDC archives. <em>Any</em> web server gives you online mode; <code class="inline">zddc-server</code> adds things a generic web server can't:</p>
|
<p style="margin-top: var(--spacing-md);"><strong><code class="inline">zddc-server</code></strong> is a small Go binary purpose-built to serve ZDDC archives. <em>Any</em> web server gives you online mode; <code class="inline">zddc-server</code> adds things a generic web server can't:</p>
|
||||||
|
|
||||||
<ul class="feature-list">
|
<ul class="feature-list">
|
||||||
<li><strong>Access control via <code class="inline">.zddc</code> files.</strong> Behind a reverse proxy that authenticates users and sets an <code class="inline">X-Auth-Request-Email</code> request header, <code class="inline">zddc-server</code> consults YAML <code class="inline">.zddc</code> files in directories — cascading bottom-up; deeper rules override. Common shapes (paired open/closed projects + third-party-restricted vendor folders) are documented with worked examples in the <a href="https://codeberg.org/VARASYS/ZDDC/src/branch/main/zddc/README.md#access-control-the-zddc-cascade">access-control reference</a>. No database, no admin UI.</li>
|
<li><strong>Access control via <code class="inline">.zddc</code> files.</strong> Behind a reverse proxy that authenticates users and sets an <code class="inline">X-Auth-Request-Email</code> request header, <code class="inline">zddc-server</code> consults YAML <code class="inline">.zddc</code> files at every directory along the path. The cascade walks root→leaf; the closest match wins. Five verbs (<code class="inline">r</code> read, <code class="inline">w</code> overwrite, <code class="inline">c</code> create, <code class="inline">d</code> delete, <code class="inline">a</code> admin / edit ACL) gate every operation. An empty grant (e.g. <code class="inline">"*@vendor.com": ""</code>) is an explicit deny. Common shapes (paired open/closed projects, third-party-restricted vendor folders) are documented with worked examples in the <a href="https://codeberg.org/VARASYS/ZDDC/src/branch/main/zddc/README.md#access-control-the-zddc-cascade">access-control reference</a>. No database, no admin UI.</li>
|
||||||
<li><strong>OPA-compatible policy decider.</strong> Federal and other regulated customers can swap the built-in evaluator for an external <a href="https://www.openpolicyagent.org/" rel="noopener">Open Policy Agent</a> server with their own audited Rego policies — set <code class="inline">ZDDC_OPA_URL</code> and the same <code class="inline">.zddc</code> files become inputs to your engine instead of ours. Wire format is OPA-canonical (<code class="inline">POST /v1/data/zddc/access/allow</code>). Default mode adds zero new dependencies; external mode is a configuration flip.</li>
|
<li><strong>Roles for human-readable grants.</strong> A <code class="inline">.zddc</code> may declare named roles whose members are email patterns; permissions then reference the role name instead of pasting the same wildcard everywhere:
|
||||||
|
<pre style="margin: 0.4rem 0;"><code>roles:
|
||||||
|
qc-reviewers:
|
||||||
|
members: ["*@quality.org", "alice@example.com"]
|
||||||
|
acl:
|
||||||
|
permissions:
|
||||||
|
qc-reviewers: rwd
|
||||||
|
"*@example.com": r</code></pre>
|
||||||
|
Role definitions cascade like everything else; a child <code class="inline">.zddc</code> redefining the same role name shadows the ancestor for that subtree.</li>
|
||||||
|
<li><strong>WORM archive folders.</strong> Anything under <code class="inline">archive/<party>/issued/</code> or <code class="inline">archive/<party>/received/</code> enforces write-once via a verb mask: ancestor grants are reduced to <code class="inline">r</code> only, while a <code class="inline">.zddc</code> placed at the WORM folder itself can still grant <code class="inline">rc</code> (create-but-not-overwrite) to specific principals — that's how a doc controller drops a fresh transmittal into the immutable record. Root admins (the <code class="inline">admins:</code> list in the root <code class="inline">.zddc</code>) bypass the mask as the deliberate escape hatch for mis-filed documents.</li>
|
||||||
|
<li><strong>Lazy folder creation, case-fold matching.</strong> Drop a <code class="inline">.zddc</code> file into an empty directory and the canonical project layout (<code class="inline">working/</code>, <code class="inline">staging/</code>, <code class="inline">archive/<party>/{mdl,incoming,received,issued}/</code>) materialises on the first write into each path — never on bare reads. Folder names are matched case-insensitively, so an existing <code class="inline">Working/</code> is reused rather than shadowed by a new <code class="inline">working/</code> sibling. Each authenticated viewer sees a virtual <code class="inline">working/<your-email>/</code> entry; first write makes it real.</li>
|
||||||
|
<li><strong>OPA-compatible policy decider.</strong> Federal and other regulated customers can swap the built-in evaluator for an external <a href="https://www.openpolicyagent.org/" rel="noopener">Open Policy Agent</a> server with their own audited Rego policies — set <code class="inline">ZDDC_OPA_URL</code> and the server POSTs the request's user, path, action, and the full <code class="inline">.zddc</code> cascade chain to <code class="inline">/v1/data/zddc/access/allow</code>. Decisions are cached per (user, path, action) with a configurable TTL (<code class="inline">ZDDC_OPA_CACHE_TTL</code>); failures fail closed by default (<code class="inline">ZDDC_OPA_FAIL_OPEN=1</code> flips it). The bundled NIST AC-6 strict-cascade preset is dumpable via <code class="inline">--print-rego=federal</code>. Default mode adds zero new dependencies; external mode is a configuration flip.</li>
|
||||||
<li><strong>Designed for regulated environments.</strong> Hardened TLS (NIST SP 800-52 Rev. 2 cipher allowlist + HSTS), pluggable policy engine, federal-mode strict-least-privilege Rego shipping out of the box, structured audit logging, documented vulnerability-disclosure process. Specific federal-track work (FIPS-validated build, signed-token proxy↔server channel, code-signed tool fetches) is on a clear roadmap — see the <a href="federal.html">federal compliance page</a> for the supported deployment shape and what an integrator adds during ATO.</li>
|
<li><strong>Designed for regulated environments.</strong> Hardened TLS (NIST SP 800-52 Rev. 2 cipher allowlist + HSTS), pluggable policy engine, federal-mode strict-least-privilege Rego shipping out of the box, structured audit logging, documented vulnerability-disclosure process. Specific federal-track work (FIPS-validated build, signed-token proxy↔server channel, code-signed tool fetches) is on a clear roadmap — see the <a href="federal.html">federal compliance page</a> for the supported deployment shape and what an integrator adds during ATO.</li>
|
||||||
|
<li><strong>Cascade tracer for operators.</strong> Admins can hit <code class="inline">/.profile/effective-policy?path=<url></code> to see the resolved ACL chain at any path — every level's grants, the role evaluation, the final verb-set. Useful when a permission isn't behaving the way the operator expected.</li>
|
||||||
<li><strong>Virtual <code class="inline">.archive</code> URL space.</strong> <code class="inline">GET /Project/.archive/123-XYZ.html</code> resolves to the canonical revision file at request time. Computed from filenames; no cache, no separate index file.</li>
|
<li><strong>Virtual <code class="inline">.archive</code> URL space.</strong> <code class="inline">GET /Project/.archive/123-XYZ.html</code> resolves to the canonical revision file at request time. Computed from filenames; no cache, no separate index file.</li>
|
||||||
<li><strong>Per-request access logging</strong> keyed to the authenticated user; conservative HTTP timeouts; optional file-tee for offline audit (production deployments typically leave logs on stdout for the orchestrator's pipeline to handle).</li>
|
<li><strong>Per-request access logging</strong> keyed to the authenticated user; conservative HTTP timeouts; optional file-tee for offline audit (production deployments typically leave logs on stdout for the orchestrator's pipeline to handle).</li>
|
||||||
<li><strong>TLS, ETags, conditional GET, CORS, autoindex.</strong> The mundane glue.</li>
|
<li><strong>TLS, ETags, conditional GET, CORS, autoindex.</strong> The mundane glue.</li>
|
||||||
|
|
@ -197,12 +209,14 @@
|
||||||
<h3>Server: just run zddc-server</h3>
|
<h3>Server: just run zddc-server</h3>
|
||||||
<p class="when">The binary has the current-stable build of all five tools baked in at compile time. They appear automatically at the right paths under <code class="inline">ZDDC_ROOT</code>:</p>
|
<p class="when">The binary has the current-stable build of all five tools baked in at compile time. They appear automatically at the right paths under <code class="inline">ZDDC_ROOT</code>:</p>
|
||||||
<ul class="install-points">
|
<ul class="install-points">
|
||||||
<li><strong>archive.html</strong> at every level (root, project, archive, vendor)</li>
|
<li><strong>archive.html</strong> and <strong>browse.html</strong> at every level (root, project, archive, party)</li>
|
||||||
<li><strong>classifier.html</strong> in any <code class="inline">Incoming</code>, <code class="inline">Working</code>, or <code class="inline">Staging</code> directory and its subtree</li>
|
<li><strong>mdedit.html</strong> in any <code class="inline">working/</code> directory and its subtree</li>
|
||||||
<li><strong>mdedit.html</strong> in any <code class="inline">Working</code> directory and its subtree</li>
|
<li><strong>transmittal.html</strong> in any <code class="inline">staging/</code> directory and its subtree</li>
|
||||||
<li><strong>transmittal.html</strong> in any <code class="inline">Staging</code> directory and its subtree</li>
|
<li><strong>classifier.html</strong> in any <code class="inline">working/</code>, <code class="inline">staging/</code>, or <code class="inline">archive/<party>/incoming/</code> subtree</li>
|
||||||
|
<li><strong>mdl.table.html</strong> at every <code class="inline">archive/<party>/</code> — the per-party Master Deliverables List, served from a built-in default schema unless the party's <code class="inline">.zddc</code> declares a custom one</li>
|
||||||
<li><strong>index.html</strong> (the project picker) at the deployment root</li>
|
<li><strong>index.html</strong> (the project picker) at the deployment root</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<p class="when" style="margin-top: 0.6rem;">Folder names are case-insensitive — <code class="inline">Working/</code>, <code class="inline">working/</code>, and <code class="inline">WORKING/</code> all match the <code class="inline">working/</code> rule.</p>
|
||||||
<pre><code>ZDDC_ROOT=/srv/zddc ./zddc-server</code></pre>
|
<pre><code>ZDDC_ROOT=/srv/zddc ./zddc-server</code></pre>
|
||||||
<p class="when" style="margin-top: 0.6rem;"><strong>To override a tool</strong> at any path: drop a real <code class="inline">.html</code> file there — that file wins over the baked-in version. <strong>To pin a different version</strong>, write an <code class="inline">apps:</code> entry in any <code class="inline">.zddc</code> file along the path:</p>
|
<p class="when" style="margin-top: 0.6rem;"><strong>To override a tool</strong> at any path: drop a real <code class="inline">.html</code> file there — that file wins over the baked-in version. <strong>To pin a different version</strong>, write an <code class="inline">apps:</code> entry in any <code class="inline">.zddc</code> file along the path:</p>
|
||||||
<pre><code># <project>/.zddc
|
<pre><code># <project>/.zddc
|
||||||
|
|
|
||||||
|
|
@ -914,19 +914,46 @@ date = 4DIGIT "-" 2DIGIT "-" 2DIGIT
|
||||||
<p>Search the deliverable's own tracking number across all transmittal folders in <code>issued/</code> and <code>received/</code>. Every folder containing that number is part of its history: which package first carried it, what the response was, which resubmittal carried the revision, and what the final outcome was.</p>
|
<p>Search the deliverable's own tracking number across all transmittal folders in <code>issued/</code> and <code>received/</code>. Every folder containing that number is part of its history: which package first carried it, what the response was, which resubmittal carried the revision, and what the final outcome was.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Section 9: Transmittal workflow -->
|
<!-- Section 9: Project layout & transmittal workflow -->
|
||||||
<section id="transmittal-workflow">
|
<section id="transmittal-workflow">
|
||||||
<h2>9. Transmittal workflow</h2>
|
<h2>9. Project layout & transmittal workflow</h2>
|
||||||
<p>Each third party (client, contractor, vendor, etc.) has a separate subfolder. All communication with that party lives in one place.</p>
|
<p>A project is a directory containing a single <code>.zddc</code> file. The server materialises the canonical folders below on the first write into them — drop a <code>.zddc</code> in an empty directory, point <code>zddc-server</code> at it, and the layout comes to life as content arrives. Folder names are matched case-insensitively, so a manually-created <code>Working/</code> is reused rather than shadowed by a new <code>working/</code>.</p>
|
||||||
|
|
||||||
<div class="code-block">
|
<div class="code-block">
|
||||||
project/
|
project/
|
||||||
{party-name}/
|
.zddc ← the only file an operator must create
|
||||||
incoming/ ← transmittals received from party, awaiting acceptance
|
working/ ← user-owned drafting workspace; mdedit
|
||||||
received/ ← permanent record of accepted transmittals from party
|
for markdown, browse for uploads.
|
||||||
issued/ ← your copies of transmittals sent to party
|
Each authenticated user with access
|
||||||
|
sees a virtual <em><your-email>/</em>
|
||||||
|
subfolder; first write materialises it.
|
||||||
|
staging/ ← outbound-transmittal preparation. A
|
||||||
|
transmittal-named mkdir here also
|
||||||
|
creates a same-named drafting folder
|
||||||
|
under working/ as a sibling space.
|
||||||
|
reviewing/ ← virtual cross-reference of in-progress
|
||||||
|
review responses; never on disk.
|
||||||
|
Notes live in working/<rs-name>/.
|
||||||
|
archive/ ← formal record of issued/received
|
||||||
|
transmittals, organised by party.
|
||||||
|
{party-name}/ ← one per counterparty AND one for
|
||||||
|
ourselves; self-folder is symmetric.
|
||||||
|
mdl/ ← Master Deliverables List for that
|
||||||
|
party. Visiting the folder opens the
|
||||||
|
table editor (<code>mdl.table.html</code>).
|
||||||
|
Default schema is built into the
|
||||||
|
server; per-party overrides via a
|
||||||
|
tables: { mdl: ./mdl.table.yaml }
|
||||||
|
entry in the party's .zddc.
|
||||||
|
incoming/ ← that party's drop point. Auto-own
|
||||||
|
.zddc grants the creator of each new
|
||||||
|
subfolder full control.
|
||||||
|
received/ ← permanent record of incoming we've
|
||||||
|
accepted (WORM — write-once read-many).
|
||||||
|
issued/ ← permanent record of what we sent to
|
||||||
|
that party (WORM).
|
||||||
</div>
|
</div>
|
||||||
<p><strong>5-step workflow:</strong></p>
|
<p><strong>5-step transmittal workflow:</strong></p>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -974,6 +1001,15 @@ project/
|
||||||
<div class="highlight-box" style="margin-top: var(--spacing-lg);">
|
<div class="highlight-box" style="margin-top: var(--spacing-lg);">
|
||||||
<p><strong>What SHA-256 gives you:</strong> Mathematical fingerprint of file contents. Single byte change → hash changes. When acknowledgment records hashes, you can verify years later that the file is identical to what was transmitted.</p>
|
<p><strong>What SHA-256 gives you:</strong> Mathematical fingerprint of file contents. Single byte change → hash changes. When acknowledgment records hashes, you can verify years later that the file is identical to what was transmitted.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3>Drafting a response transmittal</h3>
|
||||||
|
<p>Submittals from counterparties (tracking numbers containing <code>-SUB-</code> at status <code>IFR</code> or <code>IFA</code>) require a response transmittal whose status starts with <code>RS</code> (RSA, RSB, RSC, …). The drafting flow uses the same staging↔working pairing as a fresh outbound:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Create <code>staging/<YYYY-MM-DD>_<tracking> (RSA) - <title>/</code>. The date is the planned issue (response-due) date.</li>
|
||||||
|
<li>The server mirrors the folder name into <code>working/</code>; reviewer notes and the response payload are drafted there.</li>
|
||||||
|
<li>The <code>reviewing/</code> virtual surface lists each in-progress response paired with the source submittal in <code>archive/<party>/received/</code>.</li>
|
||||||
|
<li>When the response is ready, files move from <code>working/</code> into <code>staging/</code> for sign-off, then through the standard 5-step transmittal flow into <code>archive/<party>/issued/</code>. Both the staging and working folders are deleted at issue time.</li>
|
||||||
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Section 10: Tools -->
|
<!-- Section 10: Tools -->
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue