secubox-deb/packages/secubox-annuaire/debian/changelog
2026-06-30 14:51:46 +02:00

177 lines
9.8 KiB
Plaintext

secubox-annuaire (0.2.6-1~bookworm1) bookworm; urgency=medium
* feat(#768): P2 config distribution — replica-side 4R apply.
- annuaire/config_apply.py: apply a signed ConfigBlob (payload carries the
config TEXT) to <dir>/<scope>.toml through a CSPN 4R double-buffer
(shadow -> validate content_hash + TOML parse -> atomic swap -> keep
.sbx-rollback). Idempotent by version; rejects hash-mismatch / unparseable
without touching the live file. Allowlist + single-writer gating (a node
never applies a scope it published).
- annuairectl: `publish-config` (primary publishes a TOML file as a signed,
versioned blob) and `apply` (replica applies allowed blobs, run as root).
- +7 tests; suite 177 green.
-- Gerald Kerma <devel@cybermind.fr> Tue, 30 Jun 2026 18:30:00 +0200
secubox-annuaire (0.2.5-1~bookworm1) bookworm; urgency=medium
* fix(#768): correct the satellite-dashboard guard. The 0.2.4 check
`nginx -T | grep secubox-routes.d` matched config-file *comments*, not real
includes, so it wrongly removed the API drop-in and re-broke satellite
dashboards. Replaced with the robust approach: add the route, then let
`nginx -t` arbitrate — drop it back only if it duplicates a location already
active in the same (hub) vhost. nginx stays valid either way.
-- Gerald Kerma <devel@cybermind.fr> Tue, 30 Jun 2026 17:45:00 +0200
secubox-annuaire (0.2.4-1~bookworm1) bookworm; urgency=medium
* fix(#768): satellite Annuaire dashboards. The legacy nginx vhost
(sites-available/secubox) includes secubox.d/ but not secubox-routes.d/, so
the dashboard's /api/v1/annuaire/ calls fell through to the SPA shell (empty
UI on non-hub nodes). postinst now drops the API route into secubox.d/ on
those nodes (idempotent, nginx -t validated, reverted on failure); hub nodes
whose active config already includes secubox-routes.d are left untouched.
-- Gerald Kerma <devel@cybermind.fr> Tue, 30 Jun 2026 17:15:00 +0200
secubox-annuaire (0.2.3-1~bookworm1) bookworm; urgency=medium
* feat(#768): each node auto-publishes its own NodeRecord on startup.
The annuaire service (journal owner → no JWT, no write race) reads its mesh
metadata from secubox-p2p's wg_mesh.json + node.id and publishes a signed
NodeRecord into the directory, so /nodes lists the actual peers (not just
replicated offers). Idempotent: skipped when the latest record is unchanged.
Requires the node identity key from `annuairectl init`; no-op without it.
+5 tests (read_self_meta, publish-self idempotency); suite 170 green.
-- Gerald Kerma <devel@cybermind.fr> Tue, 30 Jun 2026 16:30:00 +0200
secubox-annuaire (0.2.2-1~bookworm1) bookworm; urgency=medium
* fix(#768): durable wg-mesh nft allow for the :8799 federation listener.
postinst inserts `iifname wg-mesh ip saddr 10.10.0.0/24 tcp dport 8799
accept` BEFORE the terminal drop in /etc/nftables.conf on vortex-firewall
nodes (table inet secubox_filter) so it survives reboot — a rule appended
after the drop is dead. Idempotent; guarded to mesh nodes; validated with
`nft -c` and reverted on failure. Legacy `inet filter` hubs (broad 10/8
accept) are skipped. Closes the cross-node gap where gk2 could not pull a
peer's /log/export after the peer rebooted.
-- Gerald Kerma <devel@cybermind.fr> Tue, 30 Jun 2026 15:30:00 +0200
secubox-annuaire (0.2.1-1~bookworm1) bookworm; urgency=medium
* feat: gondwana P1 distributed directory, on top of #766 (#768)
- model: NodeRecord (signed mesh peer registry, public wg key only) +
ConfigBlob (signed, versioned, single-writer config) + Op NODE_PUBLISH /
CONFIG_PUBLISH / CONFIG_REVOKE. Coexists with #766's Op.GENESIS.
- verbs: publish_node / publish_config / revoke_config + _get_nodes /
_get_configs (last-writer-wins by version → convergent across the mesh);
ingest_config; export_entries / import_entries generic log federation
(dedup by (author,sig), self-certifying binding + sig verified before
append — same defense #766 added to ingest_offer, generalized to the
whole log). resolver: config.publish right (MEMBER).
- api: GET /nodes, /config, /log/export; POST /node/publish,
/config/publish, /config/revoke, /log/pull.
- mesh_sync: in-process replication loop (the annuaire service owns the
journal → no JWT, no write race) pulling each peer's /log/export from the
#766 Gondwana mesh listener (wg-mesh-ip:8799). ANNUAIRE_DIR_SYNC=0
disables. secubox-p2p stays the peer-list owner (wg_mesh.json).
- nginx/annuaire-mesh.conf.tpl: the mesh listener now also serves
GET /log/export (signed, self-certifying, read-only) for replication —
not just /services.
- node identity reuses #766's genesis()/annuairectl/node.key (no new key
path invented). 40 directory/sync tests; full suite 167 green.
-- Gerald Kerma <devel@cybermind.fr> Tue, 30 Jun 2026 14:30:00 +0200
secubox-annuaire (0.2.0-1~bookworm1) bookworm; urgency=medium
* feat: trustless cross-node service federation (#766)
- ingest_offer now enforces the self-certifying binding
did_from_pubkey(pubkey) == offer.provider BEFORE checking the signature.
Closes the "bring your own key, claim any provider DID" forgery: the sig
alone only proves key-ownership, not that the key belongs to the claimed
provider. did:plc is sha256(pubkey)[:32], so the check needs no directory
and no prior trust in the provider.
- _get_offers / GET /services now emit self-contained, verifiable offers:
the stored payload omits sig/signer_did (not part of the signed bytes) and
never carried the pubkey, so a stranger could not verify at all. Offers now
carry sig + signer_did + provider_pubkey (transport metadata, stripped
before model reconstruction — ServiceOffer is extra=forbid).
- pull_services uses the carried provider_pubkey and feeds the now
self-certifying ingest_offer.
* feat: node bootstrap — genesis() verb + annuairectl CLI.
- genesis(): a node self-attests as a founding MEMBER (root of trust),
breaking the invite/join/subscribe chicken-and-egg. Self-certifying DID,
empty invited_by (never inflates emancipation plurality), idempotent.
- Op.GENESIS added (additive, chain-compatible).
- crypto.public_from_private(): derive pubkey from the persisted private key.
- /usr/sbin/annuairectl: init | whoami | status | offer | services | pull.
Operates the journal directly as the secubox user (no JWT for the one-time
privileged bootstrap); node key persisted 0600 in
/etc/secubox/secrets/annuaire/node.key.
* feat: Gondwana mesh federation listener (postinst-rendered).
- nginx/annuaire-mesh.conf.tpl: binds ONLY the node wg-mesh IPv4:8799,
allow 10.10.0.0/24 + deny all, exposes ONLY GET /api/v1/annuaire/services.
postinst substitutes the detected wg-mesh IP; skips install when no mesh
interface exists. postrm removes it on uninstall.
* tests: +7 federation tests (genesis member/idempotent, offer enrichment,
trustless round-trip pull, forged-pubkey + tampered-payload + bad-hex
rejection). 134 passing.
* hardening (security review): postinst validates the rendered mesh listener
with `nginx -t` and reverts it on failure so a broken render can never
persist (board-wide nginx blast radius); ship
/etc/sysctl.d/30-secubox-nonlocal-bind.conf (net.ipv4.ip_nonlocal_bind=1)
so nginx can bind the wg-mesh IP even if wg-quick@wg-mesh starts after
nginx at boot.
-- Gerald Kerma <devel@cybermind.fr> Tue, 30 Jun 2026 16:00:00 +0200
secubox-annuaire (0.1.3-1~bookworm1) bookworm; urgency=medium
* feat: service offers + subscription verbs, API and UI + pull federation
- annuaire/verbs.py: offer_service, revoke_offer, subscribe,
approve_subscription, reject_subscription, ingest_offer,
subscription_state, _get_offers, _get_offer helpers.
- api/main.py: GET /services, POST /service/offer,
POST /service/{id}/revoke, POST /service/{id}/subscribe,
GET /subscriptions, POST /subscription/{id}/approve,
POST /subscription/{id}/reject, POST /services/pull.
- www/annuaire/index.html: Services section + My subscriptions panel.
- tests/test_services.py: 28 new tests covering all security invariants.
-- Gerald KERMA <devel@cybermind.fr> Tue, 30 Jun 2026 12:00:00 +0200
secubox-annuaire (0.1.2-1~bookworm1) bookworm; urgency=medium
* ui: minimal shared-template dashboard (chain integrity, merkle root,
trust log) at /annuaire/ — also makes the module appear in the navbar.
-- Gerald KERMA <devel@cybermind.fr> Tue, 30 Jun 2026 09:30:00 +0200
secubox-annuaire (0.1.1-1~bookworm1) bookworm; urgency=medium
* security: enforce self-certifying authorship at read time (an Identity
entry only sets state for its own did:author); authorize revocation (only
self or the grafting inviter), derive REVOKED from the signed
RevocationNotice (no victim-identity forging); staged single-step
emancipation with a required founder_did. +7 adversarial tests.
-- Gerald KERMA <devel@cybermind.fr> Tue, 30 Jun 2026 09:00:00 +0200
secubox-annuaire (0.1.0-1~bookworm1) bookworm; urgency=medium
* Initial release — Annuaire-Miroir trust substrate.
- annuaire/verbs.py: auto_add / invite / accept_invite / propose / vote /
tally / revoke / emancipate — the four protocols from spec §3.
- annuaire/model.py, crypto.py, log.py, resolver.py: BLAKE2b-chained
SQLite-WAL journal + Ed25519 signing + can() resolver (pre-existing core).
- api/main.py: FastAPI on /run/secubox/annuaire.sock, JWT-gated mutating
endpoints; read endpoints public.
- Packaging: secubox-annuaire.service (User=secubox, RuntimeDirectoryPreserve=yes,
NoNewPrivileges=yes), nginx routes + static conf, menu.d, secubox.yaml.
-- Gerald KERMA <devel@cybermind.fr> Mon, 30 Jun 2026 08:00:00 +0200