<feed xmlns='http://www.w3.org/2005/Atom'>
<title>npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/src/nostr, branch master</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/atom?h=master</id>
<link rel='self' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/'/>
<updated>2026-04-10T18:20:23+00:00</updated>
<entry>
<title>fix: purgatory replacement announcements leaked into DB without git data</title>
<updated>2026-04-10T18:20:23+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-04-10T18:20:23+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=2161e3c0a8169a85111cd6dc01ffe2b0fed1493f'/>
<id>urn:sha1:2161e3c0a8169a85111cd6dc01ffe2b0fed1493f</id>
<content type='text'>
When a replacement 30617 announcement arrived for an entry already in
purgatory (e.g. the same event fetched from a second relay during sync,
or a user re-submitting a slightly updated announcement), the policy
returned Accept instead of AcceptPurgatory. This caused the event to be
saved to the database immediately, bypassing the purgatory gate, without
the corresponding git data or state events ever arriving.

Fix: return AcceptPurgatory when replacing a purgatory entry so the
updated event stays in purgatory until git data arrives. The purgatory
entry is still updated with the newer event via replace_purgatory_announcement
before the return.
</content>
</entry>
<entry>
<title>fix: accept any d-tag identifier; percent-encode in URLs</title>
<updated>2026-04-10T16:42:35+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-04-10T16:42:35+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=dfd20a39a7ddaea07103cac45d4d79bc7e6ce0d7'/>
<id>urn:sha1:dfd20a39a7ddaea07103cac45d4d79bc7e6ce0d7</id>
<content type='text'>
NIP-01 places no restriction on d tag characters and NIP-34 only
recommends kebab-case without mandating it. Rejecting identifiers with
whitespace or other URL-unsafe characters was therefore overly strict.

The correct approach (per NIP-34 PR #2312 and GRASP-01) is to store
identifiers verbatim on disk and percent-encode them when constructing
URLs. The previous commit already handled the incoming direction
(percent-decoding URL paths before filesystem lookup); this commit
handles the outgoing direction and removes the validation restriction.

Changes:
- validate_identifier: drop whitespace rejection; only reject chars
  that are unsafe as filesystem directory names (/, \, null, . / ..)
- git/mod.rs: add percent_encode() alongside percent_decode()
- landing.rs: percent-encode identifier in nostr:// clone URL and
  gitworkshop link (also fixes a pre-existing bug where the clone URL
  displayed literal '{npub}' / '{identifier}' instead of the values)
</content>
</entry>
<entry>
<title>fix: reject identifiers with whitespace and URL-decode path components</title>
<updated>2026-04-09T15:24:17+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-04-09T15:24:17+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=2d74b9ca69b3a1e0b9a2359c12cc2d1979fc6130'/>
<id>urn:sha1:2d74b9ca69b3a1e0b9a2359c12cc2d1979fc6130</id>
<content type='text'>
Two bugs allowed a repository announcement with a space-containing
identifier ('kuboslopp by Shakespeare') to enter purgatory and create
a bare repo on disk, but then fail to serve git data over HTTP.

Bug 1 (serving): parse_git_url and parse_repo_url did not percent-decode
the URL path before resolving the filesystem path. A client requesting
/npub.../kuboslopp%20by%20Shakespeare.git/info/refs had the identifier
extracted as 'kuboslopp%20by%20Shakespeare' (literal %20), which did not
match the on-disk directory 'kuboslopp by Shakespeare.git'.

Fix: add percent_decode() in src/git/mod.rs and apply it to the repo
component in both parse_git_url and parse_repo_url.

Bug 2 (validation): validate_announcement did not check that the
identifier is safe as a filesystem path component and URL segment.
Identifiers containing whitespace, path separators, null bytes, or
reserved names (. / ..) should be rejected at acceptance time.

Fix: add validate_identifier() in src/nostr/events.rs and call it from
validate_announcement before any other policy checks.
</content>
</entry>
<entry>
<title>chore: remove arbitrary default max connections limit</title>
<updated>2026-03-25T07:19:26+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-03-25T07:19:26+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=28168a7701c897a5b6af13bc472d6f5902e0a96d'/>
<id>urn:sha1:28168a7701c897a5b6af13bc472d6f5902e0a96d</id>
<content type='text'>
When NGIT_MAX_CONNECTIONS is unset the relay imposes no connection cap,
deferring to OS fd limits and infrastructure controls. The option remains
available for operators who want an explicit ceiling.
</content>
</entry>
<entry>
<title>chore: apply cargo fmt and fix clippy warnings</title>
<updated>2026-02-26T15:42:09+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-26T15:42:09+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=9d86cf15f0275ffeee4519bd054e3b61dc8992ac'/>
<id>urn:sha1:9d86cf15f0275ffeee4519bd054e3b61dc8992ac</id>
<content type='text'>
Fix pre-existing clippy lints:
- &amp;PathBuf -&gt; &amp;Path in audit_cleanup.rs
- too_many_arguments on process_newly_available_git_data,
  process_purgatory_announcements, and HttpService::new
- clone_on_copy for PublicKey (Copy type) in purgatory cleanup loop
</content>
</entry>
<entry>
<title>fix: ignore peeled tag entries (^{}) in state event ref parsing</title>
<updated>2026-02-26T15:38:51+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-26T15:38:51+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=a2ecfc5a63311570f0f90c7ee40117e289639cb8'/>
<id>urn:sha1:a2ecfc5a63311570f0f90c7ee40117e289639cb8</id>
<content type='text'>
State events (kind 30618) can include refs/tags/&lt;name&gt;^{} entries which
are git's notation for the dereferenced commit behind an annotated tag.
These are not real git refs and are never sent as part of a push.

extract_refs_from_state and RepositoryState::from_event were treating
them as real refs, causing can_satisfy_state to reject valid annotated
tag pushes: the would-be state after the push lacked the spurious ^{}
entry, so the exact-equality check always failed.
</content>
</entry>
<entry>
<title>drop nostr-db backend support, keep only lmdb and memory</title>
<updated>2026-02-25T15:07:40+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-25T15:07:40+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=5ad9d9093fcbe7037e5474a9d8fa20a0b64fb79a'/>
<id>urn:sha1:5ad9d9093fcbe7037e5474a9d8fa20a0b64fb79a</id>
<content type='text'>
</content>
</entry>
<entry>
<title>rename: fetch_repository_data -&gt; fetch_repository_data_{excluding,with}_purgatory</title>
<updated>2026-02-24T11:36:39+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-24T11:36:39+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=c31a313ccf781e54fa15942bc882c1b113d3f590'/>
<id>urn:sha1:c31a313ccf781e54fa15942bc882c1b113d3f590</id>
<content type='text'>
The old name was ambiguous - it wasn't clear whether purgatory was
included or not. The two variants are now explicitly named:
- fetch_repository_data_excluding_purgatory: DB only
- fetch_repository_data_with_purgatory: DB + purgatory overlay

SyncContext trait method also renamed to fetch_repository_data_with_purgatory
to match the free function it delegates to.
</content>
</entry>
<entry>
<title>Merge master into 3ca0-announcements-purgatory</title>
<updated>2026-02-23T15:20:59+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-23T15:20:59+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=113928aa84894ea8f65c247d9987527e792b32a9'/>
<id>urn:sha1:113928aa84894ea8f65c247d9987527e792b32a9</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat: handle deletion of PR/PR-update events from purgatory</title>
<updated>2026-02-23T13:46:57+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-23T13:46:57+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=f19b424e01fc5a682778c5e2bb194d242efd6987'/>
<id>urn:sha1:f19b424e01fc5a682778c5e2bb194d242efd6987</id>
<content type='text'>
Kind 5 deletion events referencing a PR or PR-update event by e-tag now
remove the matching purgatory entry, provided the deletion author matches
the PR event author. Placeholders (git data arrived before the event) are
not removed since they have no author to verify against.

PR purgatory is keyed by event ID hex so this is an O(1) lookup, checked
before the O(n) announcement and state event scans.
</content>
</entry>
</feed>
