Skip to content

docs(ns8): correct the install guidance and declare data handling - #156

Open
shockalotti wants to merge 1 commit into
mainfrom
docs/ns8-module-docs-and-metadata
Open

shockalotti wants to merge 1 commit into
mainfrom
docs/ns8-module-docs-and-metadata

Conversation

@shockalotti

@shockalotti shockalotti commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #156. Adds the clone-module step and documents the behaviour.

First, a correction to what I told you

I said we shipping no clone-module action was a real functional gap. It is not. NethServer/ns8-kickstart, the official module template, declares only configure-module and get-configuration, and the core ships a partial default clone-module implementation that rsyncs the volumes and state/. So cloning already worked. My framing overstated it, and I have fixed the framing rather than quietly doing the work anyway.

What the default does not handle

Two things in state/ belong to one hostname:

  • config.json — the hostname and TLS flags
  • calnode.env — BASE_URL, derived from that hostname

The Traefik route is registered by configure-module and belongs to one instance, so it is not copied; routes are keyed by MODULE_ID. A clone therefore arrives holding the source's hostname with no route of its own, and configuring it with that hostname is then refused, because the source still answers for it and configure-module refuses to steal a hostname another route already serves.

So the clone is not a clean failure. It is a quietly broken instance that looks like a configuration bug. That is worse than not supporting clone at all, which is worth saying plainly.

The step

imageroot/actions/clone-module/20unclaimhostname releases the hostname: config.json is removed and BASE_URL dropped. get-configuration then reports configured:false and the Settings page asks for a hostname, so the clone lands in exactly the state a freshly added instance is in.

It runs at 20, after the core moves data in 10recvstate and before it starts the service in 90finalize.

What it must not release is CALNODE_ENCRYPTION_KEY. It travels with the copied database and is the only thing that can unwrap the database key vault. Dropping it hands back an unreadable copy of every booking, which is strictly worse than the bug being fixed. The rewrite therefore fails loudly rather than writing an env file without the key.

Tests

8 cases in test_clone_module.py, wired into the same validate job as the existing suite, so a regression fails on every push:

  • the key survives while BASE_URL does not
  • config.json is removed
  • a missing config.json or calnode.env is not an error
  • the refusal path when the key would be lost
  • file mode stays 0600
  • comments and blank lines survive the rewrite
  • the step is idempotent, because action steps can be retried

17 tests in the packaging suite in total, all passing.

Honest caveat

This is verified by unit tests and by reading the core implementation. It has not been cloned on a real cluster. That needs a live NS8 node and the robot suite does not cover clone yet.

So I would not tell anyone a clone is supported yet. Worth adding a clone case to the robot suite before this goes out, and that is the one thing here I would want done rather than assumed.

Docs

README gains a Clone and move section, stating that the encryption key is kept and the hostname is not, and why. Better documented than discovered.

Three fixes to the module README, all of which would have cost us installs or
credibility if a reviewer had read them.

The install section told people to use :edge and not :latest, warning that
:latest was amd64-only and would fail on an arm64 node. That stopped being true
when 0.11.1 shipped: 0.11.1, 0.11 and :latest are all the same multi-arch
index. The README was still steering people away from the stable tag and onto an
unreleased build, on the strength of a warning that had already been fixed. Now
that :latest is safe, the recommendation is a pinned version tag, because that
tells you what you are running and makes updates deliberate rather than whatever
main happened to publish. :edge is described as the unreleased build, which is
what it actually is.

The same stale claim appeared a second time in the Development section, saying
:latest is currently amd64-only. Both are corrected.

"How it works" described the app image as ghcr.io/calnode/calnode:latest. It is
actually the image named by the module's org.nethserver.images label, which is
the matching app release, so the module and app cannot drift apart. Saying
:latest there was wrong for every release since the label scheme landed.

Added a Data and privacy section. It says what is stored, that the encryption
key lives in the cluster state and is never transmitted, that nothing phones
home, and, honestly, that mail and backups both hand data to whatever provider
the operator configures. That last part is the one that matters: a reader
should not have to infer it. This is what metadata.json terms_url now points at.

metadata.json also had two dead links. code_url pointed at
github.com/calnode/ns8-calnode, which does not exist and returns 404: the
module lives in the monorepo, so it now points at calnode/calnode.
documentation_url pointed at the repository root rather than any documentation;
it now points at this README, which is the administrator documentation, and is
the first thing a reviewer or an installer would want. Both URLs verified 200.

No behaviour change. Nothing here is loaded at runtime except metadata.json,
which the Apps UI reads.
@pullfrog

pullfrog Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

The model provider returned an error, so this run stopped.

The error is below. If it names your key, plan or balance, fix that with the provider or pick another model before re-triggering.

Model settings → · Ask in Discord →

provider error: This API key has expired. Create a new API key in OpenCode Console and replace it in your client or secret store. Signing in again will not renew this key.

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using space-bunny-free (free) | 𝕏

@pullfrog

pullfrog Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

The model provider returned an error, so this run stopped.

The error is below. If it names your key, plan or balance, fix that with the provider or pick another model before re-triggering.

Model settings → · Ask in Discord →

provider error: This API key has expired. Create a new API key in OpenCode Console and replace it in your client or secret store. Signing in again will not renew this key.

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using space-bunny-free (free) | 𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant