├── .builds └── nixos-latest.yml ├── .dockerignore ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── .gitlab-ci.yml ├── .license-header ├── .rustfmt.toml ├── CODEOWNERS ├── CONTRIBUTING.md ├── COPYING ├── Cargo.toml ├── DCO ├── LICENSE ├── README.md ├── TODO.md ├── bins ├── Cargo.lock ├── Cargo.toml ├── e2e │ └── git-push.sh ├── example-systemd-config │ ├── README.md │ ├── lnk-gitd.service │ └── lnk-gitd.socket ├── linkd │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── lnk-gitd │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── lnk-identities-dev │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── lnk-profile-dev │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── lnk │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── main.rs └── tests │ ├── Cargo.toml │ └── integration_test.rs ├── cli ├── gitd-lib │ ├── Cargo.toml │ ├── src │ │ ├── args.rs │ │ ├── config.rs │ │ ├── git_subprocess.rs │ │ ├── git_subprocess │ │ │ └── command.rs │ │ ├── hooks.rs │ │ ├── hooks │ │ │ ├── error.rs │ │ │ └── progress.rs │ │ ├── lib.rs │ │ ├── processes.rs │ │ ├── server.rs │ │ └── ssh_service.rs │ └── t │ │ ├── Cargo.toml │ │ └── src │ │ ├── lib.rs │ │ ├── tests.rs │ │ └── tests │ │ ├── git_subprocess.rs │ │ └── git_subprocess │ │ └── command.rs ├── linkd-lib │ ├── Cargo.toml │ ├── src │ │ ├── api.rs │ │ ├── api │ │ │ ├── announce.rs │ │ │ ├── client.rs │ │ │ ├── io.rs │ │ │ ├── messages.rs │ │ │ ├── request_pull.rs │ │ │ ├── rpc.rs │ │ │ ├── sockets.rs │ │ │ ├── wire_types.rs │ │ │ └── wire_types │ │ │ │ ├── request.rs │ │ │ │ └── response.rs │ │ ├── args.rs │ │ ├── cfg.rs │ │ ├── lib.rs │ │ ├── logging.rs │ │ ├── metrics.rs │ │ ├── metrics │ │ │ └── graphite.rs │ │ ├── node.rs │ │ ├── protocol.rs │ │ ├── request_pull.rs │ │ ├── signals.rs │ │ └── tracking.rs │ └── t │ │ ├── Cargo.toml │ │ └── src │ │ ├── gen.rs │ │ ├── lib.rs │ │ ├── tests.rs │ │ └── tests │ │ ├── api.rs │ │ ├── api │ │ └── io.rs │ │ ├── args.rs │ │ ├── cfg.rs │ │ └── tracking.rs ├── lnk-clib │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── keys.rs │ │ ├── keys │ │ │ ├── prompt.rs │ │ │ ├── ssh.rs │ │ │ └── ssh │ │ │ │ ├── unix.rs │ │ │ │ └── win.rs │ │ ├── lib.rs │ │ ├── runtime.rs │ │ ├── seed.rs │ │ ├── seed │ │ │ ├── store.rs │ │ │ └── store │ │ │ │ └── file.rs │ │ ├── ser.rs │ │ ├── socket_activation.rs │ │ ├── socket_activation │ │ │ ├── ld.rs │ │ │ └── sd.rs │ │ └── storage.rs │ └── t │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── examples │ │ ├── echo.rs │ │ ├── echo.service.in │ │ ├── echo.socket │ │ └── org.example.echo.plist.in │ │ ├── src │ │ ├── gen.rs │ │ ├── helpers.rs │ │ ├── integration.rs │ │ ├── integration │ │ │ ├── scenario.rs │ │ │ └── scenario │ │ │ │ ├── person_creation.rs │ │ │ │ └── project_creation.rs │ │ ├── lib.rs │ │ ├── properties.rs │ │ ├── properties │ │ │ ├── seed.rs │ │ │ └── seed │ │ │ │ └── store.rs │ │ ├── tests.rs │ │ └── tests │ │ │ ├── keys.rs │ │ │ └── seed.rs │ │ ├── test-ld-socket-activation.sh │ │ └── test-sd-socket-activation.sh ├── lnk-exe │ ├── Cargo.toml │ └── src │ │ ├── cli.rs │ │ ├── cli │ │ ├── args.rs │ │ └── main.rs │ │ └── lib.rs ├── lnk-identities │ ├── Cargo.toml │ ├── src │ │ ├── any.rs │ │ ├── cli.rs │ │ ├── cli │ │ │ ├── args.rs │ │ │ ├── eval.rs │ │ │ ├── eval │ │ │ │ ├── any.rs │ │ │ │ ├── local.rs │ │ │ │ ├── person.rs │ │ │ │ ├── project.rs │ │ │ │ ├── rad_refs.rs │ │ │ │ ├── refs.rs │ │ │ │ └── tracking.rs │ │ │ ├── fmt.rs │ │ │ ├── fmt │ │ │ │ └── delegate.rs │ │ │ └── main.rs │ │ ├── display.rs │ │ ├── field.rs │ │ ├── git.rs │ │ ├── git │ │ │ ├── checkout.rs │ │ │ ├── existing.rs │ │ │ ├── include.rs │ │ │ └── new.rs │ │ ├── lib.rs │ │ ├── local.rs │ │ ├── person.rs │ │ ├── project.rs │ │ ├── rad_refs.rs │ │ ├── refs.rs │ │ ├── tracking.rs │ │ └── working_copy_dir.rs │ └── t │ │ ├── Cargo.toml │ │ └── src │ │ ├── lib.rs │ │ ├── tests.rs │ │ └── tests │ │ ├── git.rs │ │ └── git │ │ ├── checkout.rs │ │ ├── existing.rs │ │ └── new.rs ├── lnk-profile │ ├── Cargo.toml │ └── src │ │ ├── cli.rs │ │ ├── cli │ │ ├── args.rs │ │ └── main.rs │ │ └── lib.rs └── lnk-sync │ ├── Cargo.toml │ └── src │ ├── cli.rs │ ├── cli │ ├── args.rs │ └── main.rs │ ├── forked.rs │ ├── lib.rs │ ├── replication.rs │ └── request_pull.rs ├── cob ├── Cargo.toml ├── src │ ├── authorizing_identity.rs │ ├── cache.rs │ ├── cache │ │ └── cached_change_graph.rs │ ├── change.rs │ ├── change_graph.rs │ ├── change_graph │ │ └── evaluation.rs │ ├── history.rs │ ├── identity_storage.rs │ ├── lib.rs │ ├── pruning_fold.rs │ ├── refs_storage.rs │ └── trailers.rs └── t │ ├── Cargo.toml │ └── src │ ├── gen.rs │ ├── helpers.rs │ ├── lib.rs │ ├── properties.rs │ ├── tests.rs │ └── tests │ ├── cache.rs │ └── cached_change_graph.rs ├── data ├── Cargo.toml ├── README.md └── src │ ├── bounded.rs │ ├── lib.rs │ └── nonempty.rs ├── default.nix ├── deny.toml ├── docs ├── maintainer-checklist.adoc ├── maintainers-guide.adoc ├── rfc │ ├── 0001-identity_resolution.adoc │ ├── 0662-collaborative-objects.adoc │ ├── 0682-application-architecture.adoc │ ├── 0685-noise.adoc │ ├── 0686-asciidoc.adoc │ ├── 0696-p2p-node.adoc │ ├── 0698-cli-infrastructure.adoc │ ├── 0699-tracking-storage.adoc │ ├── 0701-mutual-synchronisation.adoc │ ├── 0702-request-pull.adoc │ └── 0703-storage-hooks.adoc ├── spec │ ├── drafts │ │ ├── Makefile │ │ ├── out │ │ │ └── spec.css │ │ ├── pandoc │ │ │ ├── ieee-with-url.csl │ │ │ ├── spec.css │ │ │ ├── template.html │ │ │ └── template.latex │ │ ├── radicle-link-rev1-draft.md │ │ ├── references.bib │ │ └── spec.css │ ├── radicle-link.adoc │ ├── radicle-link.html │ ├── references.bib │ └── sections │ │ └── identities.adoc └── submitting-patches.adoc ├── e2e ├── Cargo.toml ├── Procfile ├── README.md ├── compose.yaml ├── linkd.dockerfile ├── prometheus │ └── config.yaml ├── quick ├── shell.nix └── src │ ├── bin │ └── ephemeral-peer.rs │ ├── lib.rs │ └── logging.rs ├── git-ext ├── Cargo.toml ├── src │ ├── blob.rs │ ├── error.rs │ ├── lib.rs │ ├── oid.rs │ ├── reference.rs │ ├── reference │ │ ├── iter.rs │ │ └── name.rs │ ├── revwalk.rs │ ├── transport.rs │ └── tree.rs └── t │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── tests.rs ├── git-helpers ├── Cargo.toml ├── src │ ├── bin │ │ └── remote │ │ │ └── main.rs │ ├── credential.rs │ ├── lib.rs │ └── remote_helper.rs └── t │ ├── Cargo.toml │ └── src │ ├── integration.rs │ ├── integration │ └── remote.rs │ └── lib.rs ├── git-ref-format ├── Cargo.toml ├── core │ ├── Cargo.toml │ └── src │ │ ├── cbor.rs │ │ ├── check.rs │ │ ├── deriv.rs │ │ ├── lib.rs │ │ ├── lit.rs │ │ ├── name.rs │ │ ├── name │ │ └── iter.rs │ │ ├── refspec.rs │ │ ├── refspec │ │ └── iter.rs │ │ └── serde.rs ├── macro │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── src │ └── lib.rs └── t │ ├── Cargo.toml │ └── src │ ├── gen.rs │ ├── lib.rs │ ├── properties.rs │ ├── properties │ ├── name.rs │ └── pattern.rs │ └── tests.rs ├── git-trailers ├── Cargo.toml ├── src │ └── lib.rs └── t │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── tests.rs ├── librad ├── Cargo.toml ├── README.md ├── src │ ├── collaborative_objects.rs │ ├── git.rs │ ├── git │ │ ├── fetch.rs │ │ ├── fetch │ │ │ └── specs.rs │ │ ├── hooks.rs │ │ ├── identities.rs │ │ ├── identities │ │ │ ├── any.rs │ │ │ ├── common.rs │ │ │ ├── error.rs │ │ │ ├── local.rs │ │ │ ├── person.rs │ │ │ ├── project.rs │ │ │ ├── project │ │ │ │ └── heads.rs │ │ │ └── relations.rs │ │ ├── include.rs │ │ ├── local.rs │ │ ├── local │ │ │ ├── transport.rs │ │ │ ├── transport │ │ │ │ └── internal.rs │ │ │ └── url.rs │ │ ├── p2p.rs │ │ ├── p2p │ │ │ └── url.rs │ │ ├── refs.rs │ │ ├── refs │ │ │ └── serde_impls.rs │ │ ├── replication.rs │ │ ├── sealed.rs │ │ ├── storage.rs │ │ ├── storage │ │ │ ├── config.rs │ │ │ ├── glob.rs │ │ │ ├── pool.rs │ │ │ ├── read.rs │ │ │ └── watch.rs │ │ ├── tracking.rs │ │ ├── tracking │ │ │ ├── odb.rs │ │ │ ├── refdb.rs │ │ │ └── v1.rs │ │ ├── types.rs │ │ ├── types │ │ │ ├── namespace.rs │ │ │ ├── reference.rs │ │ │ ├── refspec.rs │ │ │ └── remote.rs │ │ └── util.rs │ ├── internal.rs │ ├── internal │ │ └── sync.rs │ ├── lib.rs │ ├── net.rs │ ├── net │ │ ├── codec.rs │ │ ├── connection.rs │ │ ├── discovery.rs │ │ ├── peer.rs │ │ ├── peer │ │ │ ├── error.rs │ │ │ ├── storage.rs │ │ │ └── storage │ │ │ │ └── error.rs │ │ ├── protocol.rs │ │ ├── protocol │ │ │ ├── accept.rs │ │ │ ├── broadcast.rs │ │ │ ├── broadcast │ │ │ │ ├── metrics.rs │ │ │ │ └── storage.rs │ │ │ ├── cache.rs │ │ │ ├── control.rs │ │ │ ├── error.rs │ │ │ ├── error │ │ │ │ └── internal.rs │ │ │ ├── event.rs │ │ │ ├── gossip.rs │ │ │ ├── info.rs │ │ │ ├── interrogation.rs │ │ │ ├── interrogation │ │ │ │ └── rpc.rs │ │ │ ├── io.rs │ │ │ ├── io │ │ │ │ ├── codec.rs │ │ │ │ ├── connections.rs │ │ │ │ ├── error.rs │ │ │ │ ├── recv.rs │ │ │ │ ├── recv │ │ │ │ │ ├── git.rs │ │ │ │ │ ├── gossip.rs │ │ │ │ │ ├── interrogation.rs │ │ │ │ │ ├── membership.rs │ │ │ │ │ └── request_pull.rs │ │ │ │ ├── send.rs │ │ │ │ ├── send │ │ │ │ │ ├── request_response.rs │ │ │ │ │ └── rpc.rs │ │ │ │ └── streams.rs │ │ │ ├── membership.rs │ │ │ ├── membership │ │ │ │ ├── error.rs │ │ │ │ ├── hpv.rs │ │ │ │ ├── params.rs │ │ │ │ ├── partial_view.rs │ │ │ │ ├── periodic.rs │ │ │ │ ├── rpc.rs │ │ │ │ └── tick.rs │ │ │ ├── request_pull.rs │ │ │ ├── request_pull │ │ │ │ └── rpc.rs │ │ │ ├── rpc.rs │ │ │ ├── rpc │ │ │ │ ├── client.rs │ │ │ │ └── client │ │ │ │ │ ├── config.rs │ │ │ │ │ ├── error.rs │ │ │ │ │ ├── interrogation.rs │ │ │ │ │ ├── request_pull.rs │ │ │ │ │ └── streams.rs │ │ │ ├── state.rs │ │ │ ├── tick.rs │ │ │ └── tincans.rs │ │ ├── quic.rs │ │ ├── quic │ │ │ ├── connection.rs │ │ │ ├── connection │ │ │ │ └── tracking.rs │ │ │ ├── endpoint.rs │ │ │ ├── error.rs │ │ │ └── stream.rs │ │ ├── replication.rs │ │ ├── replication │ │ │ └── context.rs │ │ ├── tls.rs │ │ ├── upgrade.rs │ │ └── x509.rs │ ├── paths.rs │ ├── profile.rs │ ├── profile │ │ └── id.rs │ └── rate_limit.rs └── t │ ├── Cargo.toml │ └── src │ ├── gen.rs │ ├── gen │ ├── protocol.rs │ └── refs.rs │ ├── helpers.rs │ ├── helpers │ └── connection.rs │ ├── integration.rs │ ├── integration │ ├── scenario.rs │ ├── scenario │ │ ├── collaboration.rs │ │ ├── collaborative_objects.rs │ │ ├── default_branch_head.rs │ │ ├── menage.rs │ │ ├── passive_replication.rs │ │ ├── prune.rs │ │ ├── tracked_references.rs │ │ ├── tracking_policy.rs │ │ ├── updated_delegate.rs │ │ └── working_copy.rs │ ├── smoke.rs │ └── smoke │ │ ├── clone.rs │ │ ├── fetch_limit.rs │ │ ├── gossip.rs │ │ ├── interrogation.rs │ │ ├── regression.rs │ │ └── request_pull.rs │ ├── lib.rs │ ├── properties.rs │ ├── properties │ ├── git.rs │ ├── git │ │ ├── refs.rs │ │ └── tracking.rs │ ├── net.rs │ └── net │ │ ├── protocol.rs │ │ └── protocol │ │ ├── membership.rs │ │ └── membership │ │ └── partial_view.rs │ ├── tests.rs │ └── tests │ ├── git.rs │ ├── git │ ├── fetch │ │ └── specs.rs │ ├── include.rs │ ├── local.rs │ ├── local │ │ ├── transport.rs │ │ └── url.rs │ ├── p2p.rs │ ├── p2p │ │ └── url.rs │ ├── project.rs │ ├── refs.rs │ ├── storage.rs │ ├── storage │ │ ├── config.rs │ │ └── watch.rs │ ├── tracking.rs │ ├── types.rs │ └── types │ │ ├── namespace.rs │ │ ├── reference.rs │ │ └── remote.rs │ ├── net.rs │ ├── net │ ├── codec.rs │ ├── peer.rs │ ├── peer │ │ └── storage.rs │ ├── protocol.rs │ ├── protocol │ │ ├── broadcast.rs │ │ └── gossip.rs │ ├── tls.rs │ ├── upgrade.rs │ └── x509.rs │ ├── paths.rs │ └── profile.rs ├── link-async ├── Cargo.toml ├── src │ ├── incoming.rs │ ├── lib.rs │ ├── spawn.rs │ ├── tasks.rs │ └── time.rs └── t │ ├── Cargo.toml │ └── src │ ├── helpers.rs │ ├── lib.rs │ ├── tests.rs │ └── tests │ └── tasks.rs ├── link-canonical-derive ├── Cargo.toml └── src │ ├── internals.rs │ ├── internals │ ├── attr.rs │ └── case.rs │ └── lib.rs ├── link-canonical ├── Cargo.toml ├── src │ ├── formatter.rs │ ├── json.rs │ ├── json │ │ ├── parser.rs │ │ ├── parser │ │ │ └── string.rs │ │ └── ser.rs │ └── lib.rs └── t │ ├── Cargo.toml │ └── src │ ├── gen.rs │ ├── lib.rs │ ├── properties.rs │ ├── tests.rs │ └── tests │ ├── formatter.rs │ └── json.rs ├── link-crypto ├── Cargo.toml ├── src │ ├── keys.rs │ ├── lib.rs │ ├── peer.rs │ └── signer.rs └── t │ ├── Cargo.toml │ └── src │ ├── gen.rs │ ├── lib.rs │ ├── tests.rs │ └── tests │ ├── keys.rs │ └── peer_id.rs ├── link-git ├── Cargo.toml ├── src │ ├── lib.rs │ ├── odb.rs │ ├── odb │ │ ├── backend.rs │ │ ├── index.rs │ │ ├── index │ │ │ └── metrics.rs │ │ ├── pack.rs │ │ ├── window.rs │ │ └── window │ │ │ └── metrics.rs │ ├── protocol.rs │ ├── protocol │ │ ├── fetch.rs │ │ ├── ls.rs │ │ ├── packwriter.rs │ │ ├── take.rs │ │ ├── transport.rs │ │ ├── upload_pack.rs │ │ └── upload_pack │ │ │ └── legacy.rs │ ├── refs.rs │ ├── refs │ │ └── db.rs │ └── service.rs └── t │ ├── Cargo.toml │ └── src │ ├── integration.rs │ ├── integration │ └── protocol.rs │ ├── lib.rs │ ├── tests.rs │ └── tests │ ├── protocol.rs │ └── protocol │ ├── take.rs │ └── upload_pack.rs ├── link-hooks ├── Cargo.toml ├── src │ ├── data.rs │ ├── hook.rs │ ├── hook │ │ └── config.rs │ ├── lib.rs │ ├── sealed.rs │ └── track.rs └── t │ ├── Cargo.toml │ └── src │ ├── gen.rs │ ├── gen │ ├── data.rs │ └── track.rs │ ├── integration.rs │ ├── integration │ └── smoke.rs │ ├── lib.rs │ └── properties.rs ├── link-identities ├── Cargo.toml ├── src │ ├── delegation.rs │ ├── delegation │ │ ├── direct.rs │ │ └── indirect.rs │ ├── generic.rs │ ├── generic │ │ └── error.rs │ ├── git.rs │ ├── git │ │ ├── error.rs │ │ ├── iter.rs │ │ ├── load.rs │ │ ├── sign.rs │ │ └── tests.rs │ ├── lib.rs │ ├── payload.rs │ ├── relations.rs │ ├── sealed.rs │ ├── sign.rs │ ├── sign │ │ └── error.rs │ ├── urn.rs │ └── xor.rs └── t │ ├── Cargo.toml │ └── src │ ├── .helpers.rs.rustfmt │ ├── gen.rs │ ├── gen │ ├── generic.rs │ ├── payload.rs │ └── urn.rs │ ├── helpers.rs │ ├── lib.rs │ ├── properties.rs │ ├── properties │ ├── generic.rs │ └── urn.rs │ ├── tests.rs │ └── tests │ ├── generic.rs │ ├── git.rs │ ├── git │ ├── person.rs │ └── project.rs │ ├── payload.rs │ ├── urn.rs │ └── xor.rs ├── link-replication ├── Cargo.toml ├── src │ ├── error.rs │ ├── eval.rs │ ├── eval │ │ ├── pull.rs │ │ └── rad.rs │ ├── fetch.rs │ ├── fetch │ │ └── transitive.rs │ ├── ids.rs │ ├── internal.rs │ ├── io.rs │ ├── io │ │ ├── net.rs │ │ ├── odb.rs │ │ └── refdb.rs │ ├── lib.rs │ ├── odb.rs │ ├── peek.rs │ ├── peek │ │ ├── clone.rs │ │ └── fetch.rs │ ├── prepare.rs │ ├── refdb.rs │ ├── refdb │ │ └── mem.rs │ ├── refs.rs │ ├── refs │ │ ├── lit.rs │ │ ├── parsed.rs │ │ └── scoped.rs │ ├── sigrefs.rs │ ├── state.rs │ ├── success.rs │ ├── track.rs │ ├── transmit.rs │ └── validation.rs └── t │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── tests.rs │ └── tests │ ├── refs.rs │ └── refs │ ├── parsed.rs │ └── scoped.rs ├── link-tracking ├── Cargo.toml ├── src │ ├── config.rs │ ├── config │ │ ├── cobs.rs │ │ └── cobs │ │ │ └── cjson.rs │ ├── git.rs │ ├── git │ │ ├── config.rs │ │ ├── odb.rs │ │ ├── refdb.rs │ │ ├── refdb │ │ │ └── previous_value.rs │ │ ├── tracking.rs │ │ └── tracking │ │ │ ├── batch.rs │ │ │ ├── error.rs │ │ │ ├── policy.rs │ │ │ └── reference.rs │ ├── lib.rs │ └── tracking.rs └── t │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── properties.rs │ ├── properties │ ├── git.rs │ └── git │ │ └── config.rs │ ├── tests.rs │ └── tests │ ├── config.rs │ └── fusion.rs ├── macros ├── Cargo.toml └── src │ └── lib.rs ├── nix ├── cargo-nextest │ └── default.nix ├── ci │ ├── fmt │ └── run ├── sources.json └── sources.nix ├── scripts ├── changelog ├── ci │ ├── advisory │ ├── build │ ├── build-bins │ ├── docs │ ├── fmt │ ├── lint │ ├── macos-gnu │ ├── run │ ├── test │ └── test-fast ├── contributing │ ├── daily-mail │ ├── patch │ ├── patch-creation │ └── patch-push ├── license-headers └── render-docs ├── shell.nix ├── std-ext ├── Cargo.toml └── src │ ├── lib.rs │ ├── ops.rs │ └── result.rs └── test ├── .gitignore ├── Cargo.toml ├── README.md ├── hooks ├── Cargo.toml ├── echo-data │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── echo-forever │ ├── Cargo.toml │ └── src │ │ └── main.rs └── echo-track │ ├── Cargo.toml │ └── src │ └── main.rs ├── it-helpers ├── Cargo.toml └── src │ ├── fixed.rs │ ├── fixed │ ├── person.rs │ └── project.rs │ ├── git.rs │ ├── layout.rs │ ├── lib.rs │ ├── ssh.rs │ ├── testnet.rs │ ├── tmp.rs │ └── working_copy.rs ├── src └── lib.rs └── test-helpers ├── Cargo.toml └── src ├── gen.rs ├── gen └── std_net.rs ├── lib.rs ├── logging.rs ├── roundtrip.rs └── tempdir.rs /.builds/nixos-latest.yml: -------------------------------------------------------------------------------- 1 | image: nixos/latest 2 | sources: 3 | - https://git.sr.ht/~radicle-link/radicle-link 4 | tasks: 5 | - fmt: | 6 | cd radicle-link/ 7 | nix-shell default.nix --run ./nix/ci/fmt 8 | - lint: | 9 | cd radicle-link/ 10 | nix-shell default.nix --run ./scripts/ci/lint 11 | - advisories: | 12 | cd radicle-link/ 13 | nix-shell default.nix --run "cargo deny check advisories ||:" 14 | - licenses: | 15 | cd radicle-link/ 16 | nix-shell default.nix --run "cargo deny check licenses" 17 | - bans: | 18 | cd radicle-link/ 19 | nix-shell default.nix --run "cargo deny check bans" 20 | - sources: | 21 | cd radicle-link/ 22 | nix-shell default.nix --run "cargo deny check sources" 23 | - build: | 24 | cd radicle-link/ 25 | nix-shell default.nix --run ./scripts/ci/build 26 | nix-shell default.nix --run ./scripts/ci/build-bins 27 | - test: | 28 | cd radicle-link/ 29 | nix-shell default.nix --run ./scripts/ci/test 30 | nix-shell default.nix --run ./cli/lnk-clib/t/test-sd-socket-activation.sh 31 | - docs: | 32 | cd radicle-link/ 33 | nix-shell default.nix --run ./scripts/ci/docs 34 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .* 2 | ci 3 | docs 4 | scripts 5 | target 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .vscode 3 | tags 4 | Cargo.lock 5 | !bins/Cargo.lock 6 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - lint 3 | - build 4 | - test 5 | 6 | fmt: 7 | stage: lint 8 | image: "rustlang/rust:nightly" 9 | before_script: 10 | - rustup component add rustfmt 11 | script: 12 | - ./scripts/ci/fmt 13 | 14 | lint: 15 | stage: lint 16 | image: "rust:latest" 17 | before_script: 18 | - rustup component add clippy 19 | - apt-get update 20 | - apt-get install -y cmake 21 | script: 22 | - ./scripts/ci/lint 23 | 24 | # TODO: cargo deny (need binary install) 25 | 26 | build-stable: 27 | stage: build 28 | image: "rust:latest" 29 | before_script: 30 | - apt-get update 31 | - apt-get install -y cmake 32 | script: 33 | - ./scripts/ci/build 34 | - ./scripts/ci/build-bins 35 | 36 | test-stable: 37 | stage: test 38 | image: "rust:latest" 39 | before_script: 40 | - apt-get update 41 | - apt-get install -y cmake 42 | - cargo install cargo-nextest 43 | script: 44 | - ./scripts/ci/test 45 | 46 | build-nightly: 47 | stage: build 48 | image: "rustlang/rust:nightly" 49 | before_script: 50 | - apt-get update 51 | - apt-get install -y cmake 52 | script: 53 | - ./scripts/ci/build 54 | - ./scripts/ci/build-bins 55 | allow_failure: true 56 | 57 | test-nightly: 58 | stage: test 59 | image: "rustlang/rust:nightly" 60 | before_script: 61 | - apt-get update 62 | - apt-get install -y cmake 63 | - cargo install cargo-nextest 64 | script: 65 | - ./scripts/ci/test 66 | allow_failure: true 67 | 68 | docs: 69 | stage: build 70 | image: "rust:latest" 71 | before_script: 72 | - apt-get update 73 | - apt-get install -y cmake 74 | script: 75 | - ./scripts/ci/docs 76 | -------------------------------------------------------------------------------- /.license-header: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 The Radicle Link Contributors 2 | // SPDX-License-Identifier: GPL-3.0-or-later 3 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 100 2 | # yeap 3 | comment_width = 80 4 | wrap_comments = true 5 | hard_tabs = false 6 | tab_spaces = 4 7 | imports_layout = "HorizontalVertical" 8 | imports_granularity = "Crate" 9 | 10 | newline_style = "Unix" 11 | use_small_heuristics = "Default" 12 | 13 | reorder_imports = true 14 | reorder_modules = true 15 | 16 | remove_nested_parens = true 17 | 18 | fn_args_layout = "Tall" 19 | 20 | edition = "2018" 21 | 22 | match_block_trailing_comma = true 23 | 24 | merge_derives = true 25 | 26 | use_try_shorthand = false 27 | use_field_init_shorthand = false 28 | 29 | force_explicit_abi = true 30 | 31 | ignore = ["link-canonical/src/formatter.rs", "link-canonical/src/json/parser/string.rs"] 32 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @radicle-dev/cococo 2 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | LICENSE -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "cob", 4 | "data", 5 | "e2e", 6 | "git-ext", 7 | "git-helpers", 8 | "git-ref-format", 9 | "git-trailers", 10 | "librad", 11 | "link-async", 12 | "link-canonical", 13 | "link-canonical-derive", 14 | "link-crypto", 15 | "link-git", 16 | "link-hooks", 17 | "link-identities", 18 | "link-replication", 19 | "link-tracking", 20 | "macros", 21 | "cli/gitd-lib", 22 | "cli/linkd-lib", 23 | "cli/lnk-clib", 24 | "cli/lnk-exe", 25 | "cli/lnk-identities", 26 | "cli/lnk-profile", 27 | "cli/lnk-sync", 28 | "std-ext", 29 | "test", 30 | ] 31 | exclude = [ 32 | "bins", 33 | ] 34 | -------------------------------------------------------------------------------- /bins/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "linkd", 4 | "lnk", 5 | "lnk-gitd", 6 | "lnk-identities-dev", 7 | "lnk-profile-dev", 8 | "tests", 9 | ] 10 | -------------------------------------------------------------------------------- /bins/example-systemd-config/lnk-gitd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=lnk git daemon 3 | 4 | [Service] 5 | ExecStart= --linger-timeout 10000 --push-seeds --fetch-seeds 6 | Environment=RUST_LOG=info 7 | -------------------------------------------------------------------------------- /bins/example-systemd-config/lnk-gitd.socket: -------------------------------------------------------------------------------- 1 | [Socket] 2 | ListenStream=127.0.0.1:9987 3 | FileDescriptorName=ssh 4 | 5 | [Install] 6 | WantedBy=sockets.target 7 | -------------------------------------------------------------------------------- /bins/linkd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linkd" 3 | version = "0.1.0" 4 | edition = "2018" 5 | license = "GPL-3.0-or-later" 6 | authors = [ 7 | "xla ", 8 | ] 9 | 10 | autobins = false 11 | 12 | [[bin]] 13 | name = "linkd" 14 | doctest = false 15 | test = false 16 | 17 | [dependencies.tokio] 18 | version = "1.13.1" 19 | default-features = false 20 | features = [ "macros", "process", "rt-multi-thread" ] 21 | 22 | [dependencies.linkd-lib] 23 | path = "../../cli/linkd-lib" 24 | version = "0.1.0" 25 | 26 | [dependencies.git-tempfile] 27 | version = "1.0.6" 28 | -------------------------------------------------------------------------------- /bins/linkd/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | use linkd_lib::node::run; 7 | 8 | #[tokio::main] 9 | async fn main() { 10 | // Make sure gitoxide (including git-tempfile) does not override our signal handlers. 11 | git_tempfile::force_setup(git_tempfile::SignalHandlerMode::None); 12 | if let Err(e) = run().await { 13 | eprintln!("linkd failed: {:?}", e); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bins/lnk-gitd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lnk-gitd" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "GPL-3.0-or-later" 6 | authors = ["Alex Good "] 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | gitd-lib = { path = "../../cli/gitd-lib" } 12 | 13 | [dependencies.tokio] 14 | version = "1.10" 15 | default-features = false 16 | features = [ "fs", "io-std", "macros", "process", "rt-multi-thread", "signal" ] 17 | -------------------------------------------------------------------------------- /bins/lnk-gitd/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | #[tokio::main] 7 | async fn main() { 8 | gitd_lib::main().await 9 | } 10 | -------------------------------------------------------------------------------- /bins/lnk-identities-dev/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lnk-identities-dev" 3 | version = "0.1.0" 4 | authors = [ "Fintan Halpenny " ] 5 | edition = "2018" 6 | license = "GPL-3.0-or-later" 7 | 8 | publish = false 9 | autobins = false 10 | 11 | [[bin]] 12 | name = "lnk-identities-dev" 13 | doctest = false 14 | test = false 15 | 16 | [dependencies] 17 | anyhow = "1" 18 | 19 | [dependencies.clap] 20 | version = "3" 21 | features = [ "derive" ] 22 | 23 | [dependencies.lnk-exe] 24 | path = "../../cli/lnk-exe" 25 | 26 | [dependencies.lnk-identities] 27 | path = "../../cli/lnk-identities" 28 | -------------------------------------------------------------------------------- /bins/lnk-identities-dev/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | use clap::Parser; 7 | 8 | use lnk_exe::cli::args::Global; 9 | use lnk_identities::cli; 10 | 11 | #[derive(Debug, Parser)] 12 | pub struct Args { 13 | #[clap(flatten)] 14 | pub global: Global, 15 | #[clap(flatten)] 16 | pub identities: cli::args::Args, 17 | } 18 | 19 | fn main() -> anyhow::Result<()> { 20 | let Args { global, identities } = Args::parse(); 21 | lnk_identities::cli::main(identities, global.lnk_profile, global.lnk_ssh_auth_sock) 22 | } 23 | -------------------------------------------------------------------------------- /bins/lnk-profile-dev/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lnk-profile-dev" 3 | version = "0.1.0" 4 | authors = [ "Fintan Halpenny " ] 5 | edition = "2018" 6 | license = "GPL-3.0-or-later" 7 | 8 | publish = false 9 | autobins = false 10 | 11 | [[bin]] 12 | name = "lnk-profile-dev" 13 | doctest = false 14 | test = false 15 | 16 | [dependencies] 17 | anyhow = "1" 18 | 19 | [dependencies.clap] 20 | version = "3" 21 | features = [ "derive" ] 22 | 23 | [dependencies.lnk-exe] 24 | path = "../../cli/lnk-exe" 25 | 26 | [dependencies.lnk-profile] 27 | path = "../../cli/lnk-profile" 28 | -------------------------------------------------------------------------------- /bins/lnk-profile-dev/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | use clap::Parser; 7 | 8 | use lnk_exe::cli::args::Global; 9 | use lnk_profile::cli; 10 | 11 | #[derive(Debug, Parser)] 12 | pub struct Args { 13 | #[clap(flatten)] 14 | pub global: Global, 15 | #[clap(flatten)] 16 | pub profile: cli::args::Args, 17 | } 18 | 19 | fn main() -> anyhow::Result<()> { 20 | let Args { global, profile } = Args::parse(); 21 | lnk_profile::cli::main(profile, global.lnk_ssh_auth_sock) 22 | } 23 | -------------------------------------------------------------------------------- /bins/lnk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lnk" 3 | version = "0.1.0" 4 | authors = [ "Fintan Halpenny " ] 5 | edition = "2018" 6 | license = "GPL-3.0-or-later" 7 | 8 | autobins = false 9 | 10 | [[bin]] 11 | name = "lnk" 12 | doctest = false 13 | test = false 14 | 15 | [dependencies] 16 | anyhow = "1" 17 | 18 | [dependencies.lnk-exe] 19 | path = "../../cli/lnk-exe" 20 | -------------------------------------------------------------------------------- /bins/lnk/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | fn main() -> anyhow::Result<()> { 7 | lnk_exe::cli::main() 8 | } 9 | -------------------------------------------------------------------------------- /bins/tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tests" 3 | version = "0.1.0" 4 | authors = ["Han Xu "] 5 | edition = "2021" 6 | 7 | [dev-dependencies] 8 | pty = "0.2" 9 | serde_json = "1.0" 10 | 11 | [[test]] 12 | name = "integration_test" 13 | path = "integration_test.rs" 14 | -------------------------------------------------------------------------------- /cli/gitd-lib/src/config.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | use std::{net::SocketAddr, time::Duration}; 7 | 8 | pub use crate::hooks; 9 | 10 | pub struct Config { 11 | pub paths: librad::paths::Paths, 12 | pub signer: S, 13 | pub addr: Option, 14 | pub linger_timeout: Option, 15 | pub network: Network, 16 | } 17 | 18 | pub struct Network { 19 | /// Announce new changes on a `git receive-pack`. 20 | pub announce: Option, 21 | /// Make a request-pull call to the configured seeds on a `git 22 | /// receive-pack`. 23 | pub request_pull: bool, 24 | /// Replicate to the configured seeds on a `git upload-pack`. 25 | pub replicate: bool, 26 | } 27 | 28 | impl From<&Network> for hooks::PostReceive { 29 | fn from(net: &Network) -> Self { 30 | Self { 31 | announce: net.announce.clone(), 32 | request_pull: net.request_pull, 33 | } 34 | } 35 | } 36 | 37 | impl From<&Network> for hooks::PreUpload { 38 | fn from(net: &Network) -> Self { 39 | Self { 40 | replicate: net.replicate, 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cli/gitd-lib/src/ssh_service.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use librad::{git::Urn, git_ext}; 4 | 5 | /// A wrapper around Urn which parses strings of the form "rad:git:.git", 6 | /// this is used as the path parameter of `link_git::SshService`. 7 | #[derive(Debug, Clone)] 8 | pub(crate) struct UrnPath(Urn); 9 | 10 | pub(crate) type SshService = link_git::service::SshService; 11 | 12 | #[derive(thiserror::Error, Debug)] 13 | pub(crate) enum Error { 14 | #[error("path component of remote should end with '.git'")] 15 | MissingSuffix, 16 | #[error(transparent)] 17 | Urn(#[from] librad::identities::urn::error::FromStr), 18 | } 19 | 20 | impl std::fmt::Display for UrnPath { 21 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 22 | write!(f, "{}.git", self.0) 23 | } 24 | } 25 | 26 | impl AsRef for UrnPath { 27 | fn as_ref(&self) -> &Urn { 28 | &self.0 29 | } 30 | } 31 | 32 | impl FromStr for UrnPath { 33 | type Err = Error; 34 | 35 | fn from_str(s: &str) -> Result { 36 | match s.strip_suffix(".git") { 37 | Some(prefix) => { 38 | let urn = Urn::from_str(prefix)?; 39 | Ok(Self(urn)) 40 | }, 41 | None => Err(Error::MissingSuffix), 42 | } 43 | } 44 | } 45 | 46 | impl From for Urn { 47 | fn from(u: UrnPath) -> Self { 48 | u.0 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /cli/gitd-lib/t/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gitd-lib-test" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "GPL-3.0-or-later" 6 | 7 | publish = false 8 | 9 | [lib] 10 | doctest = false 11 | test = true 12 | doc = false 13 | 14 | [dependencies.git2] 15 | version = "0.13.24" 16 | default-features = false 17 | features = ["vendored-libgit2"] 18 | 19 | [dependencies.gitd-lib] 20 | path = "../" 21 | 22 | [dependencies.librad] 23 | path = "../../../librad" 24 | 25 | [dependencies.it-helpers] 26 | path = "../../../test/it-helpers" 27 | 28 | [dependencies.radicle-git-ext] 29 | path = "../../../git-ext" 30 | -------------------------------------------------------------------------------- /cli/gitd-lib/t/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 The Radicle Link Contributors 2 | // SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | #[cfg(test)] 5 | mod tests; 6 | -------------------------------------------------------------------------------- /cli/gitd-lib/t/src/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 The Radicle Link Contributors 2 | // SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | mod git_subprocess; 5 | -------------------------------------------------------------------------------- /cli/gitd-lib/t/src/tests/git_subprocess.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 The Radicle Link Contributors 2 | // SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | mod command; 5 | -------------------------------------------------------------------------------- /cli/linkd-lib/src/api.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | use std::{sync::Arc, time::Duration}; 7 | 8 | use tracing::instrument; 9 | 10 | use librad::{ 11 | crypto::Signer, 12 | net::{peer::Peer, protocol::RequestPullGuard}, 13 | }; 14 | use link_async::Spawner; 15 | 16 | pub use sockets::Sockets; 17 | 18 | pub mod announce; 19 | pub mod client; 20 | pub mod io; 21 | pub mod messages; 22 | pub mod request_pull; 23 | mod rpc; 24 | pub mod sockets; 25 | pub mod wire_types; 26 | 27 | #[instrument(name = "api subroutine", skip(spawner, peer, sockets))] 28 | pub async fn routine<'a, S, G>( 29 | spawner: Arc, 30 | peer: Peer, 31 | sockets: &'a Sockets, 32 | linger_timeout: Option, 33 | announce_wait_time: Duration, 34 | ) -> () 35 | where 36 | S: Signer + Clone, 37 | G: RequestPullGuard, 38 | { 39 | let tasks = Box::pin(rpc::tasks(spawner, peer, sockets.rpc(), announce_wait_time)); 40 | if let Some(timeout) = linger_timeout { 41 | link_async::tasks::run_until_idle(tasks, timeout).await 42 | } else { 43 | link_async::tasks::run_forever(tasks).await 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /cli/linkd-lib/src/api/announce.rs: -------------------------------------------------------------------------------- 1 | use librad::{git::Urn, net::protocol::gossip, PeerId}; 2 | use radicle_git_ext::Oid; 3 | 4 | #[derive(Clone, Debug, PartialEq, Eq, minicbor::Decode, minicbor::Encode)] 5 | pub struct Request { 6 | #[n(0)] 7 | pub urn: Urn, 8 | #[n(1)] 9 | pub rev: Oid, 10 | } 11 | 12 | impl Request { 13 | pub fn into_gossip(self, peer: PeerId) -> gossip::Payload { 14 | gossip::Payload { 15 | urn: self.urn, 16 | rev: Some(self.rev.into()), 17 | origin: Some(peer), 18 | } 19 | } 20 | } 21 | 22 | #[derive(Clone, Debug, PartialEq, Eq, minicbor::Decode, minicbor::Encode)] 23 | pub struct Response; 24 | -------------------------------------------------------------------------------- /cli/linkd-lib/src/api/request_pull.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use librad::{git::Urn, net::protocol::request_pull, PeerId}; 4 | 5 | #[derive(Clone, Debug, PartialEq, Eq, minicbor::Decode, minicbor::Encode)] 6 | pub struct Request { 7 | #[n(0)] 8 | pub urn: Urn, 9 | #[n(1)] 10 | pub peer: PeerId, 11 | #[n(2)] 12 | pub addrs: Vec, 13 | } 14 | 15 | #[derive(Clone, Debug, PartialEq, Eq, minicbor::Decode, minicbor::Encode)] 16 | #[cbor(transparent)] 17 | pub struct Response(#[n(0)] request_pull::Success); 18 | 19 | impl From for Response { 20 | fn from(x: request_pull::Success) -> Self { 21 | Self(x) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cli/linkd-lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | pub mod args; 7 | 8 | mod cfg; 9 | 10 | pub mod api; 11 | mod logging; 12 | mod metrics; 13 | pub mod node; 14 | mod protocol; 15 | pub mod request_pull; 16 | mod signals; 17 | pub mod tracking; 18 | -------------------------------------------------------------------------------- /cli/linkd-lib/src/metrics.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | pub mod graphite; 7 | -------------------------------------------------------------------------------- /cli/linkd-lib/src/signals.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | use tokio::{select, sync::mpsc}; 7 | use tracing::{info, instrument}; 8 | 9 | #[cfg(unix)] 10 | #[instrument(name = "signals subroutine", skip(shutdown_tx))] 11 | pub async fn routine(shutdown_tx: mpsc::Sender<()>) -> anyhow::Result<()> { 12 | use tokio::signal::unix::*; 13 | 14 | let mut int = signal(SignalKind::interrupt())?; 15 | let mut quit = signal(SignalKind::quit())?; 16 | let mut term = signal(SignalKind::terminate())?; 17 | 18 | let signal = select! { 19 | _ = int.recv() => SignalKind::interrupt(), 20 | _ = quit.recv() => SignalKind::quit(), 21 | _ = term.recv() => SignalKind::terminate(), 22 | }; 23 | 24 | info!(?signal, "received termination signal"); 25 | let _ = shutdown_tx.try_send(()); 26 | 27 | Ok(()) 28 | } 29 | 30 | #[cfg(windows)] 31 | #[instrument(name = "signals subroutine", skip(shutdown_tx))] 32 | pub async fn routine(shutdown_tx: mpsc::Sender<()>) -> anyhow::Result<()> { 33 | use tokio::signal::windows::*; 34 | 35 | let mut br = ctrl_break()?; 36 | let mut c = ctrl_c()?; 37 | 38 | select! { 39 | _ = br.recv() => info!("received Break signal"), 40 | _ = c.recv() => info!("recieved CtrlC signal"), 41 | }; 42 | 43 | let _ = shutdown_tx.try_send(()); 44 | 45 | Ok(()) 46 | } 47 | -------------------------------------------------------------------------------- /cli/linkd-lib/t/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linkd-lib-test" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "GPL-3.0-or-later" 6 | 7 | publish = false 8 | 9 | [lib] 10 | doctest = false 11 | test = true 12 | doc = false 13 | 14 | [features] 15 | test = [] 16 | 17 | [dependencies] 18 | proptest = "1" 19 | minicbor = "0.13" 20 | 21 | [dependencies.clap] 22 | version = "3" 23 | features = [ "derive" ] 24 | 25 | [dependencies.git2] 26 | version = "0.13.24" 27 | default-features = false 28 | features = ["vendored-libgit2"] 29 | 30 | [dependencies.linkd-lib] 31 | path = ".." 32 | 33 | [dependencies.librad-test] 34 | path = "../../../librad/t" 35 | features = ["test"] 36 | 37 | [dependencies.link-crypto-test] 38 | path = "../../../link-crypto/t" 39 | features = ["test"] 40 | 41 | [dependencies.link-identities-test] 42 | path = "../../../link-identities/t" 43 | features = ["test"] 44 | 45 | [dependencies.lnk-clib] 46 | path = "../../lnk-clib" 47 | 48 | [dependencies.test-helpers] 49 | path = "../../../test/test-helpers" 50 | 51 | [dev-dependencies] 52 | anyhow = "1" 53 | assert_cmd = "2" 54 | assert_matches = "1.5" 55 | futures = "0.3" 56 | nix = "0" 57 | pretty_assertions = "1.1" 58 | structopt = "0.3" 59 | tempfile = "3.3" 60 | 61 | [dev-dependencies.tokio] 62 | version = "1.13" 63 | features = ["rt-multi-thread"] 64 | 65 | [dev-dependencies.librad] 66 | path = "../../../librad" 67 | -------------------------------------------------------------------------------- /cli/linkd-lib/t/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 The Radicle Link Contributors 2 | // SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | #[cfg(test)] 5 | #[macro_use] 6 | extern crate assert_matches; 7 | 8 | #[cfg(any(test, feature = "test"))] 9 | pub mod gen; 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | -------------------------------------------------------------------------------- /cli/linkd-lib/t/src/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | mod api; 7 | mod args; 8 | mod tracking; 9 | -------------------------------------------------------------------------------- /cli/linkd-lib/t/src/tests/api.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | mod io; 7 | -------------------------------------------------------------------------------- /cli/linkd-lib/t/src/tests/cfg.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | use std::net; 7 | 8 | use anyhow::Result; 9 | use pretty_assertions::assert_eq; 10 | 11 | use linkd_lib::{Seed, Seeds}; 12 | 13 | #[tokio::test(flavor = "multi_thread")] 14 | async fn test_resolve_seeds() -> Result<()> { 15 | let (seeds, failures) = Seeds::resolve( 16 | Some( 17 | "hydsst3z3d5bc6pxq4gz1g4cu6sgbx38czwf3bmmk3ouz4ibjbbtds@localhost:9999" 18 | .parse() 19 | .unwrap(), 20 | ) 21 | .iter(), 22 | ) 23 | .await; 24 | 25 | assert!(failures.is_empty(), "seed failed to resolve"); 26 | assert!(!seeds.0.is_empty(), "seeds should not be empty"); 27 | 28 | if let Some(Seed { addrs, .. }) = seeds.0.first() { 29 | let addr = addrs.first().unwrap(); 30 | let expected: net::SocketAddr = match *addr { 31 | net::SocketAddr::V4(_addr) => ([127, 0, 0, 1], 9999).into(), 32 | net::SocketAddr::V6(_addr) => "[::1]:9999".parse().expect("valid ivp6 address"), 33 | }; 34 | 35 | assert_eq!(expected, *addr); 36 | } 37 | 38 | Ok(()) 39 | } 40 | -------------------------------------------------------------------------------- /cli/linkd-lib/t/src/tests/tracking.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 The Radicle Link Contributors 2 | // SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | use linkd_lib::tracking::{Pair, Selected}; 5 | 6 | #[test] 7 | pub fn selected_dedups() { 8 | let peer = "hynkyndc6w3p8urucakobzna7sxwgcqny7xxtw88dtx3pkf7m3nrzc" 9 | .parse() 10 | .unwrap(); 11 | let urn = "rad:git:hnrkb39fr6f4jj59nfiq7tfd9aznirdu7b59o" 12 | .parse() 13 | .unwrap(); 14 | let pair = "hynkyndc6w3p8urucakobzna7sxwgcqny7xxtw88dtx3pkf7m3nrzc,rad:git:hnrkb39fr6f4jj59nfiq7tfd9aznirdu7b59o".parse::().unwrap(); 15 | let selected = Selected::new(vec![peer], vec![urn], vec![pair.clone()]); 16 | assert!(selected.peers().next().is_none()); 17 | assert!(selected.urns().next().is_none()); 18 | assert_eq!(selected.pairs().next(), Some(&pair)); 19 | } 20 | -------------------------------------------------------------------------------- /cli/lnk-clib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lnk-clib" 3 | version = "0.1.0" 4 | authors = [ "Fintan Halpenny " ] 5 | edition = "2018" 6 | license = "GPL-3.0-or-later" 7 | 8 | [lib] 9 | doctest = false 10 | test = false 11 | 12 | [features] 13 | unsafe = [] 14 | 15 | [dependencies] 16 | async-trait = "0.1" 17 | futures = "0.3" 18 | itertools = "0.10.0" 19 | nix = "0.23.1" 20 | once_cell = "1.10" 21 | serde = "1.0" 22 | serde_json = "1.0" 23 | socket2 = "0.4.4" 24 | thiserror = "1.0" 25 | tracing = "0.1" 26 | 27 | [dependencies.librad] 28 | path = "../../librad" 29 | 30 | [dependencies.lnk-thrussh-agent] 31 | version = "0.1.0" 32 | features = [ "tokio-agent" ] 33 | 34 | [dependencies.minicbor] 35 | version = "0.13" 36 | features = ["std"] 37 | 38 | [dependencies.tokio] 39 | version = "1.17" 40 | default-features = false 41 | features = [ "fs", "io-std", "macros", "process", "rt-multi-thread", "signal" ] 42 | -------------------------------------------------------------------------------- /cli/lnk-clib/README.md: -------------------------------------------------------------------------------- 1 | # CLIB 2 | 3 | When a CLI needs a LIB, one gets a CLIB. 4 | 5 | This package provides the common data types and functions that can be 6 | used across the different set of CLI packages. 7 | 8 | * `clib::keys` - common functions for setting up of and retrival from the secret key 9 | storage. 10 | * `clib::ser` - serialization formats required for CLI output. 11 | * `clib::storage` - common functions for setting up read-only and 12 | read-write storage. 13 | -------------------------------------------------------------------------------- /cli/lnk-clib/src/keys.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | use librad::{ 7 | crypto::keystore::{crypto::Crypto, FileStorage}, 8 | profile::Profile, 9 | PublicKey, 10 | SecretKey, 11 | }; 12 | 13 | pub mod prompt; 14 | pub mod ssh; 15 | 16 | /// The filename for storing the secret key. 17 | pub const LIBRAD_KEY_FILE: &str = "librad.key"; 18 | 19 | /// Create a [`FileStorage`] for [`SecretKey`]s. 20 | pub fn file_storage(profile: &Profile, crypto: C) -> FileStorage 21 | where 22 | C: Crypto, 23 | { 24 | FileStorage::new(&profile.paths().keys_dir().join(LIBRAD_KEY_FILE), crypto) 25 | } 26 | -------------------------------------------------------------------------------- /cli/lnk-clib/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 The Radicle Link Contributors 2 | // 3 | // This file is part of radicle-link, distributed under the GPLv3 with Radicle 4 | // Linking Exception. For full terms see the included LICENSE file. 5 | 6 | pub mod keys; 7 | pub mod runtime; 8 | pub mod seed; 9 | pub mod ser; 10 | #[cfg(unix)] 11 | pub mod socket_activation; 12 | pub mod storage; 13 | -------------------------------------------------------------------------------- /cli/lnk-clib/src/seed/store.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 The Radicle Link Contributors 2 | // SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | use super::Seed; 5 | 6 | pub mod file; 7 | pub use file::{FileStore, Iter}; 8 | 9 | /// Get an iterator of the [`Seed`] in the [`Store`]. 10 | pub trait Store { 11 | type Scan: std::error::Error + Send + Sync + 'static; 12 | type Iter: std::error::Error + Send + Sync + 'static; 13 | 14 | type Addrs; 15 | type Seeds: Iterator, Self::Iter>>; 16 | 17 | /// Retrieve all [`Seed`]s in the storage. 18 | /// 19 | /// Seeds are expected to be in the following format: 20 | /// ```text 21 | /// @[,