why don't you issue the git state announcement event per NIP-34 and use that for AUTH? Then it can also be used during fetches to validate that the maintainer authorized ref state that your helper is fetching from the git server.

Reply to this note

Please Login to reply.

Discussion

right, I skipped the nip-34 because I always need to fetch it. I was only focusing on the identity part because it is only required for uploading.

full flow starts with fetching the nip-34 announcement to get the actual remote url, because it can be a GitHub url, so before considering auth I need to check that. that's done for all commands.

for upload specifically, if the remote url is pointing to a relay that supports nip34, then I try to auth. and only then allow ssh to attempt to connect.

if connection is successfully, git and ssh will do the rest.

I mean the NIP-34 git state anoucment, not the repository announcement. See https://nips.nostr.com/34#repository-state-announcements

OK, great, let's do that then. I guess I can fit that into song easily and then one will be able to just push to song using the ngit remote helper already?

At the moment the first time a maintainer pushes the nostr remote, it checks for a state announcement and if it can't find one, it creates it based off the state on the first git server listed.

I'll change that so, if the git server responds with a not found error, it creates one containing just the pushed ref(s) so it should work with that flow.

I'm trying this but it's not working.

There are no state events but it is not trying to create any, just pushing.

the repository already exists on the git server?

What do you mean by "exist"? I had never pushed it.

I havn't updated the remote helper yet so that it will push a new state event if one doesn't exist and the git server responds with a not found error (as apposed to timeout).

until I have done that you will need to have the repository on the git server, which it will use as a source for the first state event.

You mean a state event should exist on the server? Or the code should be available on the server? Does git-remote-nostr try to fetch the remote refs before pushing?

Let's suppose a remote state exists on the server, it says the branch "master" points to commit "01010202". Why is that useful if I just want to say "master" now points to "11112222"? Won't it be replaced?

the server should respond to a 'list' request with return the refs.

the remote helper tries to get the refs on the remote server so it can check if there is a conflict.

in git push should only work if its a fast-forward commit unless the `--force` flag is used.

if a state event has been issued (so state is being managed on nostr) the remote helper still checks the refs on the git server(s) to add protections to reduce the likelihood that another maintainer pushes a conflicting change at about the same time which gets overwritten.

Also covering the scenario where there owner or another maintainer starts pushing directly to the git server (by passing the state on nostr). in this case the latest conflicting changes on the git server shouldn't be automatically overwritten without the owner being warned about it.

if 01010202 is in the ancestory of 11112222 then it `git push` will work fine. if it is not, `git push --force` must be used to purposefully overwrite and potentially lose someone else's change. this is standard git.

The git remote helper also check each git server listed to ensure it is not overwriting any ones changes pushed directly to each server as sometimes the state of the git server might differ from the nostr state event.

In fact, if one of the git server(s) is ahead of the git state with conflicting changes, the user maintainer needs to push directly to that git server to overwrite the changes before they can proceed to get everything back in sync by pushing to the nostr remote.

All of this will only happen on the rare occasion that conflicting changes are pushed at about the same time or if some maintainers stop using the nostr remote as the default one.

But who does these checks? git-remote-nostr or the git server itself? Or both?

Both

The remote helper supports multiple maintainers.

It starts with the author of thr repo announcement. It then adds any pubkeys in the maintainers field. It then recursively looks up maintainers listed in any repo announcement they have with the same identifier.

It takes this list of maintainers and looks up the state event with the largest non-future `created_at` timestamp with the matching `d` identifier to identify the latest state.

oh.. I was purposefully ignoring that. since I am allowing git to get all the references from the repo itself.

what is the perceived benefit of having state outside of the repo itself? git already does a good job figuring out states for itself. doesn't that open up the possibility of eventually consistent states when fetching?

To remove trust in a git server to give you the state intended by the maintainer(s). To allow redundancy via multiple git servers.

I am out of my depth here in regards to maintaining open source repos. I need to read more about the threats that this solves. mind sharing some references?

If everyone uses a centralised git server then it is generally a trusted one. The centralised party may be obliged by a very powerful actor to push malicious commits to specific IP addresses as part of a targeted attack on a high value individual but I can point to an example of this happening. If it became public that this happened too often, it would come at a high reputational cost.

As we move away from highly centralised git servers operated by companies with a reputation to defend towards self-hosted servers or services by smaller and less know organisations, it becomes more likely that that the server could be actively malicious. our mantra is 'don't trust, verify' and our network is built on content being signed by their authors instead of a trusted third party. It there makes sense that maintainere sign repository state so we are just trusting the servers with our privacy, using the same trust model as the relays.

so this would be a way for me to validate that whatever the host server is sending me is signed states only, but requires that whoever is pushing signs an event. I think I get it now. thank you for the explanation.

my instinctive thinking is that git trees are very sensitive to unexpected changes and often plagued by conflicts over inconsistencies in the source code between remote and local copies. I am also assuming that maintainers hold the source code in a local copy. so in my mind, it is hard to force push changes that wouldn't be caught by git. then, the fact that you can just migrate your work over to a different server in a frictionless manner be enough to address the issue from the maintainers perspective, detect malicious intervention in codebase, update the repo announcement with a new remote url and it's done.

but I can understand that if we can actually prevent that from happening, by rejecting a push/fetch altogether based on a distributed state it does provide a better experience. thank you again for the explanation. I'll have to make adjustments on my side.

Yes, we touch on a well explored problem of establishing state in a distributed system (the Byzantine general problem).

the git protocol does a really good job of preventing unintentional force pushes as the state can be managed in a single place.

I originally had the remote helper push to the git servers first and only update the state event once it was accepted by all git servers listed.

But then in order to support the flow where the git server is waiting for the state event to authorise the push I started issuing the state event first.

It minimises the changes by fetching the state from all git servers immediately before issuing the state event and rejects the change if the commits can't be fast forwarded.

but if another maintainer pushes after I have completed the fetch and before I have completed the push then the state event would be out of sync with the git server.

I'm was thinking about having a `nostr.use-nostr-for-state` git config entry flag that defaults to true so that maintainers could use the remote helper without the state event element.