Publish protected nanopublications from local instances (#671) - #689
Merged
Conversation
…lications A local/private Nanopub Registry accepts, stores and serves nanopublications typed npx:ProtectedNanopub; the public network refuses them. Nanodash could already recognize such nanopublications (#671's first half); this lets users of such a deployment create them. The marker is added by an ordinary pubinfo template, so that the statement has a template behind it like every other one and round-trips through ValueFiller when a protected nanopublication is superseded, instead of being swept into the hand-coded catch-all. The template is unlisted and driven by a checkbox of its own: where a nanopublication may be stored is not a description of its content, the publication info section is behind "show more", and the generic "Nanopublication type" element produces npx:hasNanopubType, which is not what registries check -- a nanopublication that looks protected in the form would be published to the public network. The form now refuses to build one of those. Consent is about open publication, so the consent checkbox is shown only for a nanopublication that will be openly published, and says so where protection is possible. Ticking the protected box takes it away rather than rewording it: the user has one box, whose note states plainly that the nanopublication stays on the local instance. "Cannot be fully removed" would not be true there anyway -- the organization running the instance can take it off again. Protection is not the user's to turn off when the fill source or one of the templates is itself protected, or when the assertion template requires the element: the new version of a protected nanopublication would be the thing that exposes it, and a public nanopublication made with a local-only template would carry a link nobody outside can follow. Whether it is on by default is a deployment decision (NANODASH_PROTECTED_BY_DEFAULT), because both kinds of local instance exist: mostly-public ones, and private-by-default ones. The preview page shows the same box, ticked and disabled -- by then the marker is signed into the content and cannot be taken back there. Closes #671 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XwZT7hRpsCLCaJw7GCkHWy
… instance PublishNanopub.publish picks a registry from the library's own list -- bootstrap plus discovered instances, or NANOPUB_REGISTRY_INSTANCES -- which knows nothing about NANODASH_MAIN_REGISTRY. A deployment configured only the Nanodash way therefore reads from its local instance but could not publish a protected nanopublication to it: the attempt failed with "None of the available registries is a local instance" while the local instance sat right there in the config. There is only one place a protected nanopublication can go, and by the time the option is offered Nanodash has already checked that the main registry reports itself as a local instance, so it is now addressed directly. Everything else keeps going to the library's list, deliberately. Registries pull from their peers rather than pushing to them, so an openly published nanopublication sent only to a private registry would never reach the public network -- the opposite of what publishing it unprotected means. The private registry picks it up again through peering. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XwZT7hRpsCLCaJw7GCkHWy
theMarkerEndsUpInTheNanopublication builds the nanopublication the form would publish, which includes the fixed "Creator" publication info element. That element takes its value from the session user, and the session picks one up from an ORCID in ~/.nanopub -- present on a developer machine, absent on CI, where the statement stayed unfilled and NanopubCreator refused it with "Field of statement not set". The test now sets the user itself, so what it asserts no longer depends on the machine it runs on, and checks that the creator ends up in the result. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XwZT7hRpsCLCaJw7GCkHWy
Contributor
|
🎉 This PR is included in version 5.14.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second half of #671: Nanodash could already recognize protected nanopublications (the 🔒 flag, the 🔒 restricted marker); this lets users of a deployment connected to a local/private registry create them.
The marker
What registries look at is one triple,
this: a npx:ProtectedNanopub. It is added by an ordinary pubinfo template,RAjTlfGJ…(published, unlisted, no placeholders), rather than emitted in code — so the statement has ant:wasCreatedFromPubinfoTemplatelink like every other one, andValueFillerclaims it when a protected nanopublication is superseded instead of sweeping it into the hand-coded catch-all.The template is driven by a checkbox of its own rather than the "add element…" dropdown. That dropdown is behind "show more", and the generic "Nanopublication type" element produces
npx:hasNanopubType— not what registries check, so a nanopublication that looks protected in the form would go to the public network.PublishForm.checkProtectedMarkernow refuses to build one of those.One checkbox, not two
Consent is about open publication, so the consent checkbox is shown only for a nanopublication that will be openly published, and says so where protection is possible:
Ticking the protected box takes that checkbox away rather than rewording it. The user has one box, and its note is a statement of fact: "This nanopublication will stay on the local instance this Nanodash is connected to." The public wording would not be true there — "cannot be fully removed" holds for the public network, not for one instance whose operators can take it off again.
The preview page shows the same box, ticked and disabled: by then the marker is signed into the content.
When it is not the user's choice
ProtectedNanopubs.getForcedReason— the fill source is protected (the new version repeats its content), a template the form is built on is protected (a public nanopublication would carry a link nobody outside can follow), or the assertion template lists the element innt:hasRequiredPubinfoElement. The checkbox is then ticked and disabled with the reason shown. If protection is forced or defaulted on and the template cannot be loaded, publishing is refused rather than silently downgraded to public.Defaults
NANODASH_PROTECTED_BY_DEFAULT(orprotectedByDefaultin the preferences file), because both kinds of local instance exist: mostly-public ones with occasional protected content, and private-by-default ones.Second commit: where it is sent
PublishNanopub.publishpicks from the library's own registry list, which knows nothing aboutNANODASH_MAIN_REGISTRY. A deployment configured only the Nanodash way read from its local instance but could not publish a protected nanopublication to it — "None of the available registries is a local instance", with the local instance sitting in the config.Utils.publishNanopubnow addresses protected nanopublications togetMainRegistryUrl()directly.Unprotected ones keep going to the library's list, deliberately: registries pull from their peers rather than pushing to them, so an openly published nanopublication sent only to a private registry would never reach the public network.
Verification
1323 tests, 0 failures (+21). Beyond the unit tests, driven end to end against a local stack (registry 1.12.1 + query 1.28.0, both
LOCAL_INSTANCE=true), from a deployment deliberately configured withoutNANOPUB_REGISTRY_INSTANCES— the case that used to fail:https://w3id.org/np/RA5-gEQNLlun_V1QVV6pbzedbRBzSXY5_4x5fJXM8nCcUPublishing protected nanopublication to the configured local instance: http://localhost:19292/this: a npx:ProtectedNanopuband the template link; Nanodash renders it back with the 🔒 flagDesign notes in
docs/protected-nanopublications.md.Known gaps
Closes #671
🤖 Generated with Claude Code
https://claude.ai/code/session_01XwZT7hRpsCLCaJw7GCkHWy