Blogs on Sourcehut https://sourcehut.org/blog/ Recent content in Blogs on Sourcehut Hugo -- gohugo.io en Mon, 01 Dec 2025 00:00:00 +0000 Proposed price increases for SourceHut https://sourcehut.org/blog/2025-12-01-proposed-pricing-changes/ Mon, 01 Dec 2025 00:00:00 +0000 https://sourcehut.org/blog/2025-12-01-proposed-pricing-changes/ <p>As we wrap up our end-of-year budget here at SourceHut, we find ourselves with a good opportunity to reconsider our pricing. We have always promised to evaluate any potential pricing changes in consultation with our community, which is why we&rsquo;re bringing our proposal forward to you now for discussion. We&rsquo;re looking forward to hearing your thoughts!</p> <p><strong>tl;dr</strong>: We want to increase the base rates to €4/€8/€12, with current users grandfathered into their current rates. Furthermore, users in the EU who pay in US dollars will soon have to pay VAT when we rehome them with our EU business. Free service is still available to users who can&rsquo;t pay. Read on for more details!</p> <hr> <p><em>New here? SourceHut is a software development platform which offers repository hosting, bug tracking, continuous integration, mailing lists, and more to projects hosted with us. SourceHut is 100% free and open source software. Welcome!</em></p> <hr> <p>SourceHut&rsquo;s pricing has been the same since we first started accepting payments in 2018: $2, $5, and $10 per month, with a &ldquo;2 months free&rdquo; discount for users who pay annually. There is no difference between the price tiers; we use an honor-system model of &ldquo;pay what you think is fair&rdquo; based on your financial means and how much you use SourceHut.</p> <p>In the years since, inflation has effectively reduced the prices by 30%. All of you have been subject to the same inflation and stagnant wages in the meantime, and we have preferred to take the hit to our margins rather than pass the costs onto you in an increasingly stressed economy. But, at some point, we will have to consider raising our prices.</p> <p>Before we get into the proposed changes, I&rsquo;d first like to reiterate that SourceHut is committed to <strong>never</strong> pricing anyone out of our services. If you cannot afford to pay for your account for any reason, then you are eligible for free service by applying for financial aid.</p> <p>Our proposal is to set the standard prices for new customers from January 2026 onwards in Euro at €4, €8, and €12, and in US dollars at $5, $10, and $15.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> In addition to these standard rates, the billing UI will be updated to offer a reduced rate of €2/$2 (the same as the present-day minimum payment) in addition to financial aid as an option for users who cannot pay the standard rates.</p> <div class="side-by-side"> <a href="https://redacted.moe/f/118a53ca.png"> <img alt="Screenshot of the new payment flow, showing the standard pricing as well as a prompt to view alternatives." src="https://redacted.moe/f/118a53ca.png" /> </a> <a href="https://redacted.moe/f/ecde5d60.png"> <img alt="Screenshot of the second page of the new payment flow, showing the subsidized rate and offering financial aid as an option." src="https://redacted.moe/f/ecde5d60.png" /> </a> </div> <div class="caption"> A mock-up of changes to payment process shows the offer of a reduced rate hidden behind a button click. Click to view the images at full size. </div> <p>Users with an existing paid subscription will be grandfathered into their current price indefinitely. If you cancel your paid subscription and sign up again later, you&rsquo;ll pay the new price. Users who pay at a grandfathered price point will also get a notice in their billing profile asking them to volunteer to pay the new price:</p> <p><img src="https://redacted.moe/f/8048839d.png" alt="A screenshot of the prompt to upgrade your account"></p> <h2 id="moving-us-accounts-to-europe">Moving US accounts to Europe</h2> <p>One more change to prices coming up soon: as many of you know, we are in the process of moving our business from the US to Europe. Our US business was below the thresholds required to charge VAT, so users in Europe have not been charged VAT up until now. However, our European business is of course required to charge VAT to European customers. As we shutter the US business entity and move these customers to our European business, we will have to start charging VAT for customers in the EU.</p> <p>If your account is affected, you can expect to receive an email with the details at least 3 months prior to your account being migrated. You will have an opportunity to choose a lower price tier (or a higher one, for that matter), or cancel your subscription, before VAT is applied to your renewal payments. Your payment will still be denoted in US dollars, though you will have the option to switch to paying in Euro.</p> <p>Customers who are already paying in Euro are already being charged VAT, so if you&rsquo;re one of them then there will be no changes for your account.</p> <p>There are still a number of technical hurdles to overcome planning this rollout, so the exact timeline is uncertain, but we&rsquo;re hoping to complete this by Q2 &ndash; and finally close our US business shortly thereafter! 🇪🇺🎉</p> <h2 id="why-do-we-need-to-raise-prices">Why do we need to raise prices?</h2> <p>As briefly explained at the top, we have not adjusted our prices for inflation since our inception, and that means that our margins have been steadily shrinking as the costs of doing business have gone up. SourceHut is still profitable and sustainable today, but for our long-term financial health it is necessary to increase our revenue.</p> <p>The price increases proposed exceed the price changes you would expect if we simply adjusted for inflation. The rationale is:</p> <ol> <li>These prices are future-proof, so we don&rsquo;t have to change prices frequently.</li> <li>This allows us to offer established users the option to remain at their current price point, making up for it with new subscriptions and users who volunteer to pay the higher rates.</li> <li>The extra revenue gives us more resources to invest in SourceHut. With more revenue we are better able to invest in infrastructure upgrades, new services and features, and in our staff. Our staff makes below market salaries (standardized at €2800/month), and while we probably won&rsquo;t be paying ourselves market rates any time soon, it would be nice to increase our compensation modestly, or hire additional staff, with the extra revenue.</li> </ol> <p>As always, all of our profits are always invested 100% back into free and open source software.</p> <p>Also: we&rsquo;re planning on putting together a new financial transparency report soon, so you&rsquo;ll have more insights into our finances and how the new prices are working out when the time comes.</p> <h2 id="share-your-thoughts">Share your thoughts?</h2> <p>This proposal, all of its finer details and broad strokes, are up for discussion with the SourceHut community. That includes you! Please let us know your thoughts. We&rsquo;re discussing it on IRC, on the #sr.ht channel on Libera Chat, and on the sr.ht-discuss mailing list <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%[email protected]%3E">in this thread</a>. We&rsquo;re looking forward to hearing your thoughts.</p> <hr> <p><em>Updated 2025-12-02: Clarify the situation around who will owe VAT.</em></p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>As we move our primary business into the EU, our base pricing is reckoned in Euro. Prices for other currencies like US dollars are selected by taking the current exchange rate from Euro and rounding the figures towards an attractive price gradient. Note that you can also pay in the currency of your choice and let your bank do the conversion from your native currency if your bank offers a good exchange rate.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on SourceHut? Q4 2025 https://sourcehut.org/blog/2025-11-20-whats-cooking-q4-2025/ Thu, 20 Nov 2025 00:00:00 +0000 https://sourcehut.org/blog/2025-11-20-whats-cooking-q4-2025/ <p>Hi everyone! We hope you&rsquo;re reading today&rsquo;s update under as many blankets as possible, ideally in front of a warm fireplace, as the cold of winter starts to set in. You may have read our <a href="https://sourcehut.org/blog/2025-09-01-whats-cooking-q3-2025/">last update</a> in the third quarter &ndash; it&rsquo;s time again to take a look at what&rsquo;s new and what&rsquo;s next.</p> <h2 id="drews-update">Drew&rsquo;s update</h2> <p>I&rsquo;ve been knee deep in refactoring over the past few months, and it has been very rewarding. The pile of tech debt has been steadily shrinking! Two of the goals I mentioned in my last status update were met: first, I rolled out <a href="https://github.com/mirumee/ariadne-codegen">ariadne-codegen</a> to all of our frontends to handle their GraphQL requests to each other (and to their own backends) and I have found that it improves the frontend code substantially. And, the one we&rsquo;ve been waiting years for: the legacy REST API has finally been removed (almost) entirely 🎉</p> <p>There is still one internal user of the legacy API, which is a legacy webhook subscription used by all services to receive account updates from meta.sr.ht. Completely paying back all of the tech debt incurred by supporting the legacy API is blocked on the removal of this last piece of the puzzle. Conrad and I are debating a few ways to replace it &ndash; do we add a user details cache, do we have services fetch user data from meta every time they need it, or do we upgrade it to a GraphQL webhook, or do some other thing? Ideally we like to reduce the number of sources of truth so that we don&rsquo;t have to worry about them disagreeing with one another &ndash; the solution we come up with in the end is something that will have to wait until the next quarter&rsquo;s update to become clear.</p> <p>Speaking of the next quarter, I am planning on working on more user-facing improvements. In particular, I have plans to introduce first-class support for commit trailers into the git.sr.ht API as well as into the lists.sr.ht&rsquo;s API for patchsets. Based on this work I will be updating the project hub to more tightly integrate the various components of SourceHut projects together, for instance by adding ticket references when a patch mentioning them is being discussed on the mailing list. The main motivator for working on this, however, is to add a commit trailer that lets you identify the dependencies of a patch which are not yet merged upstream, and have the CI pull those patches down when testing your work.</p> <p>The other user-facing changes I mentioned in the last update, such as an improved profile page on the project hub, or FIDO/U2F support for two-factor auth, are still planned for the near term and I hope to find time for them in the coming months. Multiple email addresses may end up being on hold until we figure out what to do with the internal legacy user profile update thing.</p> <p>Another large change I&rsquo;ve made is to our process for handling tickets related to SourceHut itself. Each of the old bug trackers, one per service, has been closed to submissions and we&rsquo;ve declared a sort of bankruptcy on all of the tickets that were there &ndash; we were not keeping up with it and many of them were duplciates, obsolete, or irrelevant. Instead we now have <a href="https://todo.sr.ht/~sircmpwn/sourcehut">a single &ldquo;sourcehut&rdquo; bug tracker</a>. I retrieved most of the tickets worth saving from the old bug trackers, and organized them onto this new one, which we are now attempting to better maintain so that you can get a view of our priorities. If we missed any tickets you cared about, please let us know on the <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss mailing list</a>.</p> <p>One last treat for you before I let Conrad take the mic: just this week I put out an overhaul for our <a href="https://man.sr.ht/installation.md">install docs</a>, for those of you who want to run your own SourceHut instance. I won&rsquo;t pretend that SourceHut is any easier to install than it has ever been, but these docs should give experienced sysadmins a better starting point for their deployments. Enjoy!</p> <h2 id="conrads-update">Conrad&rsquo;s update</h2> <p>Welcome back to the department of under-the-hood improvements! I certainly have some treats for you this time around.</p> <p>As hinted at last time, we&rsquo;ve made great progress with our Ceph cluster. The Alpine upgrade in the previous quarter unlocked an upgrade of Ceph itself, which I performed this quarter. We are now on Ceph 18 (&ldquo;Reef&rdquo;). There was another round of Alpine upgrades, too, so the path to Ceph 19 (&ldquo;Squid&rdquo;) is clear. Though I am not sure it will still happen this year. We are prudent with the Ceph version we are running and not in a rush&hellip;</p> <p>The absolute highlight for me this quarter, however, was finally dropping Alembic from our stack! It has been completely replaced by <a href="https://git.sr.ht/~sircmpwn/sourcehut-migrate">sourcehut-migrate</a>, and we are quite happy with the result. The whole operation went smoothly, but there is one little regression: the <code>xxx.sr.ht-initdb</code> scripts got dropped without proper replacements. But fear not: I am almost done implementing an alternative solution in <code>sourcehut-migrate</code>!</p> <p>As is customary, I will sprinkle in some user-facing changes: we enabled <a href="https://graphql.org/learn/introspection/">GraphQL introspection</a> on all services. This facilitates the usage of various GraphQL tools to work with our API, without having to feed them with our schemas first.</p> <p>Another one that only few users will care about, but those probably all the stronger: lists.sr.ht finally supports emails in non-UTF8 encodings. I don&rsquo;t think this was ever a conscious decision, it was just a few bits and pieces missing, but now it should be fixed. While we&rsquo;d certainly still appreciate everyone switching to UTF8, we did not mean to lock anyone out.</p> <p>Incidentally, I think the most prominent cause of encoding issues was in fact folks importing old(ish) mailing list archives from elsewhere. So while this will hopefully improve the process, there is still plenty of other reasons why an import might fail. But I have good news about that, too: lists.sr.ht will now send you an email if an import fails, providing you with actionable details.</p> <p>Going back under the hood, I played a bit with <a href="https://golangci-lint.run">golangci-lint</a>. While we had tons of rather uninteresting warnings, it also did uncover a few very valid issues. So I bit the bullet and cleaned up the entire Go codebase to the point that we now run <code>golangci-lint</code> in CI, so that hopefully no new issues will creep in.</p> <p>We also moved one more of our ancillary services to Kubernetes: there is now <a href="https://mirror.srht.network">mirror.srht.network</a>, which will soon replace <a href="https://mirror.sr.ht">mirror.sr.ht</a>. Right now we only use it for infrastructure-related packages, but with the next Alpine upgrade we will likely switch completely, allowing us to shut down yet another VM.</p> <p>Last but not least, if you&rsquo;re still reading, your attention span is certainly long enough, so why not take a look at our new <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%[email protected]%3E">build worker RFC</a>. I cannot take credit for all the ideas put forth in there, but as I sort of started driving this I&rsquo;ll take the opportunity to solicit feedback from you, the community. Because the TL;DR is that we want to allow you, the community, to run your own build workers! Wouldn&rsquo;t that be a nice user-facing feature for me to write about?</p> <h2 id="everyone-else">Everyone else</h2> <p>SourceHut is 100% free and open source software, and the community is invited to participate in its development. Let’s take a moment to acknowledge the work of the volunteers who use and depend on SourceHut and sent along patches to improve it over the past few months.</p> <p><a href="https://simartin.dev/">Simon Martin</a> has been hard at work on dozens of bug fixes and little improvements, and also found the time to develop some nice features, too: thanks to his efforts you&rsquo;ll now find a little checkbox on your <a href="https://lists.sr.ht">lists.sr.ht dashboard</a> which will cause the mailing list software to copy you on your own emails, if you prefer for it to. We&rsquo;re not quite done reviewing his work on this next one, but soon we&rsquo;ll be rolling out another feature he developed which allows you to narrow the conditions under which build jobs are submitted, such as omitting feature branches from CI in your git repos. Simon also fixed a long-standing problem with the project hub recently, de-duplicating events so that an email sent to one mailing list shared among many projects does not fill their event logs up with dozens of events. Thanks, Simon!</p> <p>It&rsquo;s been a relatively slow quarter for distro releases, so the workload of our volunteer build image maintainers has been pretty light. But I&rsquo;d like to thank Maxell G for handling the roll-out of Fedora 44 as the new Rawhide release, and the EOL of Fedora 40, and to welcome Alex Kramer as the new maintainer of our Arch Linux images.</p> <p>There were dozens of other small patches in the past couple of months, fixing little bugs or making small improvements all over SourceHut, from many different contributors. Thank you to everyone who played a part in making SourceHut better!</p> <hr> <p>Thanks for reading our update &ndash; we welcome you to discuss it on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a> if you have comments or feedback. See you again in Q4!</p> What's cooking on SourceHut? Q3 2025 https://sourcehut.org/blog/2025-09-01-whats-cooking-q3-2025/ Mon, 01 Sep 2025 00:00:00 +0000 https://sourcehut.org/blog/2025-09-01-whats-cooking-q3-2025/ <p>Hello everyone! It&rsquo;s time for another quarterly update on what we&rsquo;re up to at SourceHut. There&rsquo;s a lot of great stuff going on since <a href="https://sourcehut.org/blog/2025-05-29-whats-cooking-q2/">you last heard from us</a>! Let&rsquo;s get started.</p> <h2 id="drews-update">Drew&rsquo;s update</h2> <p>We finally <a href="https://sourcehut.org/blog/2025-07-10-pay-in-euro/">rolled out</a> the billing overhaul! God, that was <em>so much</em> work. Since the announcement in July we have successfully accepted a couple hundred payments in Euro &ndash; thank you to everyone for your support! The rollout was nearly flawless, with just a few things to sort out here and there and just few embarrassing problems to deal with (a fun one: a handful of users got invoices with a &ldquo;SAMPLE&rdquo; watermark).</p> <p>There are still some knock-on things to deal with for billing, especially when our Q3 tax bill is due, but most of it is not user-impacting. We&rsquo;ll probably roll out a couple of new payment currencies and move all users to our European entity by the end of the year (which will, unfortunately, come with an annoying price increase for some users who will start being charged VAT, you&rsquo;ll get an email before that happens if you&rsquo;re affected). Other than that, the billing plans are now pleasantly unremarkable.</p> <p>Now that I&rsquo;m free of the huge pile of billing work, I&rsquo;ve been spending most of my time aggressively paying back tech debt, as promised in previous updates. The biggest change in this respect is that we&rsquo;re getting serious about removing the legacy REST API in favor of GraphQL. All of the API documentation has been removed, the meta.sr.ht functionality for registering new legacy OAuth clients and personal access tokens has been removed, and I have done an analysis of contemporary legacy API usage and removed all of the API features which are not still in active use. There are about 30 users who are still relying on the legacy API &ndash; I have emailed them to inform them of the looming removal of the legacy API and offered to assist in migrating them to GraphQL. Please check your inbox if you&rsquo;re one of them!</p> <p>Unfortunately one of those contemporary users of the legacy API is ourselves. I have been working to reduce internal consumers of the legacy API over the past few months, upgrading bits of the project hub, the build submitter for hg.sr.ht, rewriting how man.sr.ht communicates with git.sr.ht, and so on. It&rsquo;s a work in progress but I&rsquo;m making good strides towards refactoring all of the remaining code &ndash; at this point we&rsquo;re down to a few legacy webhooks, and those are a bit more complicated to replace.</p> <p>I&rsquo;ve also been looking into some more experimental changes. A big one that I&rsquo;ve been researching is using <a href="https://github.com/mirumee/ariadne-codegen">ariadne-codegen</a> to generate GraphQL clients for our Python frontends to use to talk to their own backends and the APIs of other services with which they integrate. A long term goal is to remove our frontend&rsquo;s access to the database and get rid of SQLAlchemy, and having our frontends communicate with GraphQL for their work &ndash; providing a single source of truth for business logic and database access. Making this work well requires us to have a robust approach to GraphQL clients in the frontend code &ndash; and Ariadne seems to be a promising option for that. I&rsquo;m getting ready to roll it out for meta.sr.ht&rsquo;s frontend for a start later this week.</p> <p>I&rsquo;ve been up to a few other things &ndash; I&rsquo;ve replaced our dependency on minio&rsquo;s Go SDK to talk to radosgw with the AWS SDK instead, for all of our services that speak to S3. That includes git.sr.ht and builds.sr.ht artifacts, as well as pages.sr.ht&rsquo;s basic functionality. Since we moved from minio to radosgw, it had seemed a bit odd for us to continue to depend on the minio client SDK as well. I also replaced our dependency on the now-deprecated go-yaml/yaml with goccy/go-yaml, which had some knock-on effects that were resolved with ~meroje&rsquo;s help.</p> <p>There&rsquo;s a bunch of little things all over the place that I&rsquo;ve improved in my quest to pay back our tech debt &ndash; more than I can elaborate on any further without boring you. I plan to continue my work in the coming months, but I will also be working on some new features for you. Some small, nice-to-have features that I have planned include support for multiple registered email addresses on your account, as well as webauthn (FIDO/U2F) support for 2FA. I also intend on overhauling the project hub&rsquo;s profile page, to act as a sole unified page for your profile across all services &ndash; which should reduce some confusion and give you a nice page to show off your work.</p> <h2 id="conrads-update">Conrad&rsquo;s update</h2> <p>For me as well, finally, some of the long-term work is coming to fruition! The first one is the site-wide rollout of <a href="https://git.sr.ht/~sircmpwn/sourcehut-ssh">sourcehut-ssh</a>, our new unified SSH ingress. This is of course one of those under-the-hood changes, but it will make life a lot easier going forward for both admins and developers. It will also be the foundation for our planned SSH ingress handling in Kubernetes.</p> <p>Another one, hinted at in the last update, is <a href="https://git.sr.ht/~sircmpwn/sourcehut-migrate">sourcehut-migrate</a>, our anticipated Go replacement for Alembic. It has already been rolled out for pages.sr.ht (which was not actually using Alembic before), but with paste.sr.ht the first switch is in the pipeline as well.</p> <p>A more user-facing highlight are some of the improvements to the GraphQL playground. My part in that was actually quite a while ago, adding support for variables and making some minor UI improvements. Conveniently, that prompted Drew to add a field providing the currently composed query as a <code>curl</code> request, providing a simple entrypoint for scripting. He also replaced the unannotated schema definition on that page with an integration of <a href="https://docs.sourcehut.org">docs.sourcehut.org</a>. We hope that all this will help people adopt and experiment with our GraphQL API.</p> <p>Our monitoring infrastructure also got some upgrades: <a href="https://metrics.srht.network">metrics.srht.network</a> is now on Prometheus 3 and we added a <a href="https://ntfy.sh/">ntfy.sh</a> sink to alertmanager. The latter is not public (for now) and the alerts will require some tuning to the new use cases that this opens up, but it definitely already improves incident response.</p> <p>However, my personal highlight for this quarter - and this may sound odd at first - was performing a full Alpine Linux upgrade and subsequent reboot on one of our two Ceph cluster nodes, without any interruption whatsoever. You see, Ceph is not <em>really</em> designed to be operated at this small scale. But we cannot afford a whole server zoo just for storage. Ever since its inception, SourceHut has been operating with a single storage server (initially not Ceph). The anticipated redundancy has always been disk-level, not server-level (we have off-site backups for that). Not too long ago, we added a second storage server, and with this we <em>still</em> don&rsquo;t have full server-level redundancy. But what we are able to do now is shuffle data around so that we can temporarily take down one server in a very controlled fashion. I feel like it took me a Ph.D. in Cephology to achieve this, so I am now busy writing a lot of documentation. But since this is something that every Ceph expert will (somewhat rightfully) tell you you shouldn&rsquo;t be doing, I am also very happy right now that I learned the Ceph internals well enough to get it to work at all. Because offsite backups are cool, but upgrades without downtime are even cooler&hellip; ;)</p> <h2 id="everyone-else">Everyone else</h2> <p>SourceHut is 100% free and open source software, and the community is invited to participate in its development. Let&rsquo;s take a moment to acknowledge the work of the volunteers who use and depend on SourceHut and sent along patches to improve it over the past few months.</p> <p>First of all, as always our build image maintainers have been hard at work. Taavi Väänänen has been keeping an eye on the Debian builds, fixing some issues with recent upstream Debian changes and shipping a Trixie image. ~arusekk was kind enough to send along an Alpine 3.22 patch as well. As Drew mentioned earlier, ~meroje also sent us a small improvement for our updated YAML parser, which makes round-trips a bit prettier when your build manifests are edited by e.g. git.sr.ht prior to submission.</p> <p>Thomas Chauchefoin has once again generously sent us a number of security bug reports, most of which had patches attached. Thanks Thomas! If you&rsquo;re running your own SourceHut instance, make sure you&rsquo;re subscribed to the <a href="https://lists.sr.ht/~sircmpwn/sr.ht-admins">sr.ht-admins</a> mailing list to get notified about these issues.</p> <p>Simon Martin has also continued his work on various SourceHut improvements &ndash; chronicled in weekly updates <a href="https://simartin.dev/blog/">on his blog</a>. Simon fixed a few small bugs and added minor features all over the place, such as showing the branch name on man.sr.ht footers to help contributors figure out where to find the code for your wikis, or fixing race conditions that prevent lists.sr.ht from threading messages properly. Notably Simon also added some heuristics for auto-detecting new patch versions and superseding the old versions automatically &ndash; very convenient! In related lists.sr.ht news, Robin Jarry also stopped by this quarter to continue some maintenance work on the lists.sr.ht-ingress daemon.</p> <p>Big thanks to everyone to worked to make SourceHut better this quarter!</p> <hr> <p>Thanks for reading our update &ndash; we welcome you to discuss it on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a> if you have comments or feedback. See you again in Q4!</p> SourceHut is now accepting payments in Euro https://sourcehut.org/blog/2025-07-10-pay-in-euro/ Thu, 10 Jul 2025 00:00:00 +0000 https://sourcehut.org/blog/2025-07-10-pay-in-euro/ <p>I&rsquo;m pleased to announce that, as part of our broader plans to migrate SourceHut to Europe, and after <a href="https://sourcehut.org/blog/2025-05-29-whats-cooking-q2/">many</a> <a href="https://sourcehut.org/blog/2025-03-07-whats-cooking-q1-25/">months</a> of hard work, SourceHut has begun to accept subscription payments in Euro today &ndash; one of our oldest and most highly demanded feature requests. The pricing is similar to the US dollar pricing at €2, €5, and €10 per month (slightly more expensive than USD due to the Euro&rsquo;s purchasing power),<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> with two months free if you pay annually. We have added support for SEPA direct debits, iDEAL, and Bancontact.</p> <p>As before, payment remains optional for <a href="https://sourcehut.org/pricing#service-availability">most SourceHut features</a> (and many features still do not even require an account). Financial support is available for those who cannot afford the lowest subscription tier. SourceHut remains committed to <strong>never</strong> pricing anyone out: hundreds of people have applied for and received financial aid for any number of reasons. Please <a href="mailto:~sircmpwn/[email protected]">apply for support</a> if your situation requires it.</p> <p>On the other hand, all users who have the means to support SourceHut are kindly asked to do so, provided that the <a href="https://sourcehut.org/alpha-details">public alpha</a> has reached a level of maturity equal to their needs. SourceHut depends entirely on our users for support, which keeps us accountable to them first and foremost. We have never accepted private investors and we cannot be pressured to compromise on our values, on user privacy, or on our commitment to publishing 100% open source software, thanks to the generous support of our community.</p> <p>We are pleased to integrate deeper into the European community, and upgrading the billing system to support the Euro is the next big step in that direction. We are now running almost all of our infrastructure in Europe,<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> and moving our revenue to Euro and our business operations to the Netherlands is another step towards completing our move from the United States.</p> <p>Thank you as always to everyone our community for your generous support &ndash; to those who pay for their subscription, but also to the hundreds of people who collaborate with us on our open source codebase, volunteer maintainers of many of SourceHut&rsquo;s subsystems, and all of the people who host their projects here, or contribute to those projects.</p> <h2 id="faq">FAQ</h2> <h3 id="which-payment-methods-are-available">Which payment methods are available?</h3> <p>We accept payments in Euro via:</p> <ul> <li>Credit card</li> <li>SEPA direct debit (IBAN)</li> <li>iDEAL</li> <li>Bancontact</li> </ul> <h3 id="will-you-support-more-currencies">Will you support more currencies?</h3> <p>Yes. The work to make our system multi-currency generalizes to other currencies. We intend to support GBP and JPY soon and we will add others as well. If you would like to request that we prioritize your currency of choice, please email <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a>.</p> <h3 id="will-you-support-more-payment-methods">Will you support more payment methods?</h3> <p>It depends. We have added all of the Euro-based payment methods that we care to, but as we introduce other currencies we will endeavour to support the payment methods most suitable for those currencies. If you have a payment method you prefer, please email <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a> to propose it.</p> <p>Note that we have already evaluated and elected not to support PayPal and cryptocurrency.</p> <h3 id="will-you-accept-cash-or-bank-transfers-again">Will you accept cash or bank transfers again?</h3> <p>Once upon a time, we accepted annual payments in cash at each year&rsquo;s FOSDEM, and we would accept manual bank transfers as well. Both methods have the advantage of not requiring nonfree JavaScript to support. We have not ruled out accepting payments in this manner again in the future, but for right now we have no concrete plans to do so.</p> <h3 id="i-pay-in-usd-now-can-i-switch-to-euro">I pay in USD now, can I switch to Euro?</h3> <p>Not yet: presently Euro is only accepted for new subscriptions. We will be making it possible to change your payment currency in the near future.</p> <p>Workaround: if your subscription term ends within the next couple of months, you may cancel your paid subscription and sign up again in Euro when it runs out.</p> <h3 id="why-is-sourcehut-moving-to-europe">Why is SourceHut moving to Europe?</h3> <p><em>Drew, speaking for himself:</em></p> <p>The most straightforward explanation for why SourceHut is moving to Europe is that, since I moved to the Netherlands, all of SourceHut&rsquo;s staff live in Europe. And because we don&rsquo;t use the cloud &ndash; we colocate servers that we assembled and own ourselves &ndash; it also just made sense to move our infrastructure to Europe, to be located close to the sysadmins responsible for it.</p> <p>This simple explanation obscures the reasons why I personally moved to Europe. Indeed I moved myself, and SourceHut, to Europe in part for strategic business reasons: the European open source community is stronger than the US, and moreover I believe that we have a competitive advantage in subjecting ourselves to tough European laws and regulations regarding privacy and consumer protections &ndash; our users would demand this level of attention to their needs regardless.</p> <p>There are personal reasons, as well, for moving myself to Europe, thus starting a process that would naturally lead to SourceHut&rsquo;s business and operations moving with me. When I moved out of the United States, back in 2021, I was moving away from a political and social landscape that I no longer felt comfortable being a part of. I expanded on these feelings in detail <a href="https://drewdevault.com/2021/06/07/The-Netherlands.html">on my personal blog at the time</a>. To my dismay, the years since have shown that my foresight in this matter was prudent.</p> <p>I sleep better knowing that my business isn&rsquo;t being coerced into complicity with the US Gestapo, or implementing policies that would be letting down our queer and trans users, women, or people of color who use SourceHut. We feel that we can provide a safer service to our community from Europe, moving user data and SourceHut staff out of the reach of US institutions.</p> <h3 id="what-are-your-plans-for-winding-down-the-us-legal-entity">What are your plans for winding down the US legal entity?</h3> <p>The process is gradual and conservative, as our revenue and therefore our ability to provide useful services to our customers depended, until now, on our US legal entity being able to process payments. We have adopted a cautious approach to make sure that we continue to have the resources we need to provide reliable service.</p> <p>All customers who signed up prior to today are still having their payments processed through the US system. Once we establish confidence in the European system we&rsquo;ve built, and normalized our processes and procedures at low volume, we will prepare to migrate all existing users to the European payment processing system. This is expected to take place by the end of the year.</p> <p>We have one more server in the US, which is used for off-site backups. Backup data on this server is encrypted in Europe before being sent off-site. We will likely de-provision this server in the foreseeable future, but it is not a particularly high priority.</p> <p>Once these steps are complete it is our intention to dis-incorporate the US legal entity and cease operations in the United States entirely.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>This is, in part, an intentional inflation adjustment given that we have not updated our prices in 7 years.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>All that remains is one server used for encrypted off-site backups.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on SourceHut? Q2 2025 https://sourcehut.org/blog/2025-05-29-whats-cooking-q2/ Thu, 29 May 2025 00:00:00 +0000 https://sourcehut.org/blog/2025-05-29-whats-cooking-q2/ <p>Hello everyone! We&rsquo;re back with <a href="https://sourcehut.org/blog/2025-03-07-whats-cooking-q1-25/">another quarterly update</a> for you on how things are going at SourceHut. It&rsquo;s been a busy few months, and we&rsquo;re happy to share what we&rsquo;re working on with you all.</p> <h2 id="drews-updates">Drew&rsquo;s updates</h2> <p>As readers of my personal blog might have noticed when I posted <a href="https://drewdevault.com/2025/03/17/2025-03-17-Stop-externalizing-your-costs-on-me.html">my LLM rant</a> in mid-March, my assessment in the Q1 update that the LLM scrapers were &ldquo;more or less under control&rdquo; was a bit optimistic. Since then, I <em>think</em> that we have actually gotten it under control after <a href="https://sourcehut.org/blog/2025-04-15-you-cannot-have-our-users-data/">deploying the nuclear option</a> (<a href="https://anubis.techaro.lol/">Anubis</a>). A few weeks after this blog post, I moved us from Anubis to <a href="https://git.gammaspectra.live/git/go-away">go-away</a>, which is more configurable and allows us to reduce the user impact of Anubis (e.g. by offering challenges that don&rsquo;t require JavaScript, or support text-mode browsers better). We have rolled this out on several services now, and unfortunately I think they&rsquo;re going to remain necessary for a while yet &ndash; presumably until the bubble pops, I guess.</p> <p>Thankfully, the success of Anubis and go-away in mitigating the LLM bots problem has finally allowed me to spend most of my time on our real priorities, which is why I&rsquo;m getting ready to ship a huge batch of billing upgrades next week. I&rsquo;ve been hard at work (1) upgrading our Stripe integration to the latest Stripe APIs, and (2) moving most of it into meta.sr.ht&rsquo;s GraphQL API. You can expect to see major user-facing improvements in the billing UX from next week onwards.</p> <p>It&rsquo;s kind of difficult to overstate how much work has gone into the billing system upgrades. The billing system was very simple and unsophisticated prior to all of this work, and the new system is much more capable, flexible, and maintainable &ndash; but getting there is a lot of work. Most of it is not obvious to users, since we have to move slowly and carefully to avoid recklessly breaking our revenue sources (or nasty bugs like overcharging users), but this batch of changes will bring the first big group of obvious user-facing improvements. I also encourage you to play with the GraphQL API a bit when this ships next week &ndash; the new billing system is designed with an API-first mindset and so a lot of its knobs and dials are available to you to play with.</p> <p>After this big patch series lands in production, I have some more internal (non-user-facing) work to do to move our payment processing into the EU, but it should be relatively soon that we&rsquo;re able to add the single longest-awaited feature of the billing upgrades: support for more payment methods, like iDEAL and SEPA transfers. This effort saw its first signs of life recently &ndash; last week I collected a payment via iDEAL in my development environment!</p> <p>Billing (and bot control) have been my two major focus areas this quarter, but I have done a little bit here and there, so I&rsquo;ll briefly summarize those other accomplishments. A small improvement to the GraphQL APIs includes the addition of better standardized errors, so that you can distinguish error conditions on the client side &ndash; for example, readily distinguishing &ldquo;not found&rdquo; from &ldquo;access denied&rdquo; in your GraphQL client.</p> <p>In more colorful news, I have installed a server in my bike shed at home. This may seem odd to include here, but I thought I&rsquo;d mention it because I have used it to replicate an infrastructure environment comparable to SourceHut production, with ceph, libvirt, and k8s all making an appearance. I&rsquo;ve moved many of the services I rely on privately in my personal infrastructure constellation from The Cloud (VPS providers) to the shed, such as NextCloud, Immich, and Miniflux. I&rsquo;m using this setup mainly to learn more about ceph and k8s in an environment that has realistic production constraints (I actually need this stuff to work!) but which I can more confidently experiment on without breaking anything for SourceHut users. I hope to apply this experience to help Conrad with his efforts to roll out upgrades to the SourceHut fleet &ndash; which I&rsquo;ll let him share with you now.</p> <h2 id="conrads-updates">Conrad&rsquo;s updates</h2> <p>This time around I&rsquo;ll start with the rather tangible items: first, I am happy to announce that the <a href="https://srht.site">pages.sr.ht</a> API has gained basic support for ACLs. It&rsquo;s not really well documented yet - and only works for custom domains - but <a href="https://docs.sourcehut.org/pages.sr.ht#field-updateSiteACL">it is possible</a> to allow other users to publish your site. We are using this ourselves to collectively publish <a href="https://docs.sourcehut.org">docs.sourcehut.org</a>. Pending some better documentation, we hope that this feature may make it easier for teams using SourceHut until there is proper groups support.</p> <p>Sort of descending into the infrastructure realm, but still tangible: we made the repository that hosts our Kubernetes infrastructure <a href="https://git.sr.ht/~sircmpwn/gensokyo">public</a>. After the <a href="https://sourcehut.org/blog/2024-01-19-outage-post-mortem/">DDoS</a>, we became a bit cautious about publishing details about our infrastructure. However, we think it&rsquo;s time to be more transparent about our operations again. This repository is only the stuff that runs in Kubernetes, which isn&rsquo;t that much yet. But it will become much more, and we will evaluate publishing other bits and pieces over time.</p> <p>Speaking of Kubernetes, this is may be a good time to lay out the current plans. Much preparation work has happened, and there are currently two distinct milestones we hope to reach soonish.</p> <p>One is to route all incoming sr.ht traffic through the Kubernetes ingress controller. In the background, much or even most of the traffic might still be handled by the service VMs. But it would provide much better visibility into sr.ht as a whole, and would give us easy knobs to turn when experimenting with running services in Kubernetes. To achieve this milestone we need to change all service&rsquo;s DNS records to point to the ingress nodes, but that means they&rsquo;ll also have to handle incoming SSH connections. Hence, the main thing missing is the unified SSH dispatch handler that is currently in review. For sr.ht, we will probably end up employing an SSH ingress solution that leverages the power of CephFS, but we&rsquo;ll take care to keep things working for smaller instances (or those simply not using Ceph).</p> <p>The second milestone would be running one actual service completely in Kubernetes. I was initially entertaining the idea that it could be meta, but for various reasons it will probably be something else. Regardless of the service, there are a few things missing. First, the service&rsquo;s Redict instance will have to be migrated from the on-VM instance to the new network-wide sentinel-based cluster. This way, VMs and pods can share a cache, which is important for some services. Then, of course, there need to be containers. Those are conceptually straightforward, but some minor things will still need adjustment (like the currently chosen-at-random Prometheus port for observing the work queue flushing). Also, a first attempt to add Containerfiles sparked some ideas about our repository layouts, so we may take the occasion to clean those up a bit.</p> <p>Most of my other work is also still in-flight. We&rsquo;ve added another server to our Ceph cluster, but the big Ceph upgrade is still to come. And I am evaluating Go-based database migration frameworks, so we can throw out even more Python code (alembic).</p> <h2 id="everyone-else">Everyone else</h2> <p>I&rsquo;d like to set out a spot here in our quarterly updates going forward to talk about what all of you have been doing for SourceHut! We&rsquo;re a free software project after all, and we regularly accept contributions from our users.</p> <p>First, I&rsquo;d like to thank our tireless builds.sr.ht image maintainers &ndash; most of our builds.sr.ht images are maintained by members of their respective communities (i.e. Fedora images are maintained by Fedora users, not SourceHut). Haowen Liu, Maxwell G, Hugo Osvaldo Barrera, CismonX, and Cayetano Santos all shipped updates to, respectively, Ubuntu, Fedora, OpenBSD, FreeBSD, and Guix this quarter, with Cayetano stepping up as the new Guix maintainer &ndash; and we&rsquo;re seeing off Unwox with a big thanks for all of their work on Guix support to date.</p> <p>In addition to his work on builds.sr.ht, Hugo Osvaldo Barrera added a long-awaited feature allowing users to rename more resources on SourceHut and set up the appropriate redirects, such as projects on the project hub. Long time contributor наб also made an appearance in this quarter to land a bunch of small improvements, such as improving to diff rendering on git.sr.ht and lists.sr.ht, and building a more sophisticated git-over-HTTP implementation &ndash; nice to have you back, наб! Eli Schwartz also returned to revisit his favorite subject, namely making SourceHut more deterministic in support of downstream distributions that download and checksum resources from SourceHut.</p> <p>I&rsquo;d also like to thank Simon Martin for making their first contributions to SourceHut this quarter, landing numerous small improvements to lists.sr.ht, such as access control improvements which allow users to update the status of their own patchsets. Be sure to read <a href="https://simartin.dev/blog/20250415/">Simon&rsquo;s blog post</a> about the experience!</p> <p>There were many other small contributions from our community this month &ndash; thank you to everyone who helped to make SourceHut better!</p> <hr> <p>Thanks for reading our update &ndash; we welcome you to discuss it on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a> if you have comments or feedback. See you again in Q3!</p> You cannot have our user's data https://sourcehut.org/blog/2025-04-15-you-cannot-have-our-users-data/ Tue, 15 Apr 2025 00:00:00 +0000 https://sourcehut.org/blog/2025-04-15-you-cannot-have-our-users-data/ <p>As you may have noticed, SourceHut has deployed <a href="https://anubis.techaro.lol">Anubis</a> to parts of our services to protect ourselves from aggressive LLM crawlers.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> Much ink has been spilled on the subject of the LLM problem elsewhere, and we needn&rsquo;t revisit that here. I do want to take this opportunity, however, to clarify how SourceHut views this kind of scraper behavior more generally, and how we feel that the data entrusted to us by our users ought to be used.</p> <p>Up until this point, we have offered some quiet assurances to this effect in a few places, notably our terms of service and robots.txt file. Quoting the former:</p> <blockquote> <p>You may use automated tools to obtain public information from the services for the purposes of archival or open-access research. You may not use this data for recruiting, solicitation, or profit.</p> </blockquote> <p>This has been part of our terms of service since they were originally written in 2018. With the benefit of hindsight, I might propose a different wording to better reflect our intentions &ndash; but we try not to update the terms of service too often because we have to send all users an email letting them know we&rsquo;ve done so. I have a proposed edit pending to include in the next batch of changes to the terms which reads as follows:</p> <blockquote> <p>You may use automated tools to access public SourceHut data in bulk (i.e. crawlers, robots, spiders, etc) provided that:</p> <ol> <li>Your software obeys the rules set forth in robots.txt</li> <li>Your software uses a User-Agent header which clearly identifies your software and its operators, including your contact information</li> <li>Your software requests data at a rate which does not negatively affect the performance of our services for other users</li> </ol> <p>You may <em>only</em> collect this data for one or more of the following purposes:</p> <ul> <li>Search engine indexing</li> <li>Open-access research</li> <li>Archival</li> </ul> <p>You may not use automated tools to collect SourceHut data for solicitation, profit, training machine learning models, or any other purpose not enumerated here without explicit permission from SourceHut staff.</p> </blockquote> <p>This text, or something similar, will be included in our next update to the terms of service, which will probably ship around the time we finish setting up our new European billing system.</p> <p>A careful observer can see our views on scrapers elaborated on in our <a href="https://git.sr.ht/robots.txt">robots.txt</a> file as well. It begins as follows:</p> <pre tabindex="0"><code># Our policy # # Allowed: # - Search engine indexers # - Archival services (e.g. IA) # # Disallowed: # - Marketing or SEO crawlers # - Anything used to feed a machine learning model # - Bots which are too agressive by default. This is subjective, if you annoy # our sysadmins you&#39;ll be blocked. # # If you do not respect robots.txt or you deliberately circumvent it we will # block your subnets and leave a bag of flaming dog shit on your mother&#39;s front # porch. </code></pre><p>One can infer from the tone of the last sentence that attempting to enforce robots.txt is a frustrating, thankless task for our sysadmins.</p> <p>To add to these resources, I&rsquo;d like to elaborate a bit more on our views on scrapers for you today. Scrapers have been a thorn in the side of sysadmins for a very long time, but it&rsquo;s particularly important as LLM scrapers seize the entire Internet to feed into expensive, inefficient machine learning models &ndash; ignoring the copyright (<a href="https://nitter.net/mitsuhiko/status/1410886329924194309">or copyleft</a>, as it were) of the data as they go. The serious costs and widespread performance issues and outages caused by reckless scrapers has been on everyone&rsquo;s mind in the sysadmin community as of late, and has been the subject of much discussion online.</p> <p>Aside from the much-appreciated responses of incredulity towards LLM operators, and support and compassion for sysadmins from much of the community, a significant minority views this problem as less important than we believe it to be. Many of their arguments reduce to victim blaming &ndash; that it&rsquo;s not that hard to handle this volume of traffic, that we should be optimized to better deal with it, that we need more caching or to improve our performance, or that we should pay a racketeer like CloudFlare to make the problem go away. Some suggest that sysadmins should be reaching out to LLM companies to offer them more efficient ways to access our data to address the problem.</p> <p>Of course, not all software is necessarily able to be as resource efficient as Joe Naysayer&rsquo;s static website. Moreover, LLM companies are not particularly interested in the more expensive route of building software integrations for each data source they scrape when they could go the cheap route of making us all pay for the overhead; nor should us sysadmins have to spend the finite time and resources at <em>our</em> disposal (often much more modest than the resources available to these LLM companies) negotiating with terrorists and building bespoke solutions for <em>them</em>.</p> <p>More important than any of these concerns is to address the underlying assumption: that these companies are entitled to this data. This assumption has varied roots, as benign as misplaced Libertarian ideals and as unhinged as the Rationalism cult belief that AGI is around the corner and everyone ought to be participating as best they can for the benefit of untold numbers of unborn future-humans.</p> <p>It is our view that these companies are <em>not</em> entitled to the data we provide, nor is anyone else. The intended audience for the publicly available data on SourceHut is users of and contributors to open source software who are accessing the data for those purposes. Indeed some profitable use of public SourceHut data is permitted, as one is entitled to by the <a href="https://opensource.org/osd">Open Source Definition</a>, but we do not wish to provide our data in bulk for any business, megacorp or startup alike, who wants to feed it into an LLM or do anything else with it which does not directly serve our mission, which is to improve open source software.</p> <p>We would not come to a special arrangement to share this data with any of these companies, either, even in the unlikely event that they offered to pay for it. We are funded by paid subscriptions, not by selling our user&rsquo;s data. It is not ours to sell &ndash; something GitHub, with its own LLM products, would do well to consider more carefully. The data we have been entrusted with belongs to our users, and is dedicated to the commons, and we take our role as the stewards of this data seriously. It is our duty to ensure that it is used in the service of our users best interests. <a href="https://sourcehut.org/blog/2019-10-23-srht-puts-users-first/">We have always put them first</a>.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>We&rsquo;re also researching <a href="https://git.gammaspectra.live/git/go-away">go-away</a>, a new option which may be effective with a reduced user impact (notably by not necessarily requiring JavaScript).&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> Announcing docs.sourcehut.org https://sourcehut.org/blog/2025-03-27-announcing-docs-sourcehut-org/ Thu, 27 Mar 2025 00:00:00 +0000 https://sourcehut.org/blog/2025-03-27-announcing-docs-sourcehut-org/ <p>Today, I&rsquo;d like to show off our new documentation site dedicated to SourceHut&rsquo;s (and hence <a href="https://sr.ht">sr.ht</a>&rsquo;s) GraphQL APIs: <a href="https://docs.sourcehut.org">docs.sourcehut.org</a>.</p> <p>Our work to move from the legacy REST API to a <a href="https://graphql.org/">GraphQL</a> API is still ongoing, and certain features we are aiming for (such as <a href="https://graphql.org/learn/federation/">federation</a>) are still missing. Nevertheless, it is already the best - and preferred - way to programatically interact with SourceHut instances.</p> <p>If you&rsquo;ve never used GraphQL before, there will be a slight learning curve. But we aim to make our documentation as helpful as possible, for beginners and experts alike.</p> <p>At the core of each GraphQL API, there is a <a href="https://graphql.org/learn/schema/">schema</a> that defines the data types and operations that the API makes available. This schema can be considered a machine readable API documentation. The schema language also has first-class support for comments, to make it more accessible to humans as well. Yet, even with comments, the presentation of a raw schema is not exactly the most ergonomic way for a human to learn about an API.</p> <p>However, given that all information is contained in the schema in a machine-readable way, it is quite easy to transform it into a form that is much more suitable for human consumption. Such tools are called GraphQL documentation generators. There are plenty of them out there, and we evaluated several. But none really checked all the boxes we were aiming for:</p> <ul> <li>Entire API output on a single page, so <code>Ctrl</code> + <code>f</code> is useful</li> <li>Little to no JavaScript</li> <li>Good support for custom <a href="https://graphql.org/learn/schema/#directives">directives</a></li> <li>Not too opinionated about the CSS/HTML structure</li> </ul> <p>And so, I couldn&rsquo;t resist: I wrote <a href="https://git.sr.ht/~bitfehler/gockel">my own</a>. You almost can&rsquo;t call it a documentation generator, because it does nothing but throwing a specific object at a template you have to supply. But this also makes it powerful: the template has access to pretty much any aspect of the provided schema. These templates are key here, so if you are interested, you can find the templates for our documentation at <a href="https://git.sr.ht/~bitfehler/docs.sourcehut.org">git.sr.ht/~bitfehler/docs.sourcehut.org</a>.</p> <p>Given that we probably would have ended up writing a bunch of templates anyway (to properly customize the output of other tools), the result is pretty satisfying. Gockel is an extremely simple tool, and it will be easy to add features should the need arise. The underlying schema object that it exposes contains a <em>lot</em> of information, so there are many avenues to explore for improving the documentation.</p> <p>Even though we ended up not using it, I would like to give credit to <a href="https://github.com/anvilco/spectaql">spectaql</a> - it was the most promising candidate out of the existing tools I evaluated, and the current layout of docs.sourcehut.org is certainly inspired by its default theme.</p> <p>For now, I hope <a href="https://docs.sourcehut.org">docs.sourcehut.org</a> will help you navigate SourceHut&rsquo;s API. We are just getting started here, so there are likely some rough edges. If you find any bugs or have any ideas for improvement, please <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">let us know</a>.</p> What's cooking on SourceHut? Q1 2025 https://sourcehut.org/blog/2025-03-07-whats-cooking-q1-25/ Fri, 07 Mar 2025 00:00:00 +0000 https://sourcehut.org/blog/2025-03-07-whats-cooking-q1-25/ <p>Hello all! We&rsquo;re back with another &ldquo;What&rsquo;s cooking&rdquo;, after another too-long hiatus since <a href="https://sourcehut.org/blog/2024-09-16-whats-cooking-september-2024/">September</a>. We did promise to resume monthly updates, but in hindsight that seems a bit ambitious given everything on our plate. For now we&rsquo;re going to aim for the more modest ambition of publishing updates quarterly.</p> <h1 id="drews-updates">Drew&rsquo;s updates</h1> <p>My work has been proceeding as expected since September, with significant disruptions due to the LLM bot crisis, which to my consternation has occupied a substantial amount of time I would have rather spent on more important priorities. Nonetheless, I am happy to report that we have more or less got the bot crisis under control &ndash; though it consumed nearly all of my attention for several weeks, I can now occasionally enjoy up to several days in a row without one of our services being knocked out by LLM scrapers.</p> <p>In any case, I finished the git webhook upgrades I mentioned in September, though for now there is no option for a webhook recipient to intervene to prevent a push from proceeding. I&rsquo;ve taken advantage of this and other GraphQL-native webhooks besides to make inroads towards updating our internal users of the legacy API, notably by moving the project hub to the new API and porting over the first webhooks from the legacy system to GraphQL webhooks.</p> <p>A matter of greater interest to most users is the upgrades I&rsquo;ve been gradually rolling out for the billing system. There are numerous improvements in the pipeline, including support for more payment methods (e.g. iDEAL, SEPA bank transfers, etc) and more currencies (in particular Euro). But, this is a time-consuming process of gradual improvements and migrations. The billing system has been largely untouched since it was originally written in 2018, and there are thousands of paying users whose payments we&rsquo;re processing every day, and we need those payments to flow correctly to keep the lights on. Each improvement is as small as possible and is carefully reviewed and monitored as it&rsquo;s rolled out to ensure that the system works correctly without interruption.</p> <p>This work is part of the bigger picture work to move SourceHut entirely from the US to the EU, in particular by processing payments through our European entity and in accordance with European laws and regulations. We&rsquo;re getting there! I hope to continue this work through the rest of March, with the ambitious goal of accepting our first payments in Euro in Q1 (but, more realistically, early Q2… it&rsquo;s a lot of work).</p> <p>In addition to billing work, my main focus for the next quarter will be paying down more tech debt, and in particular finishing the deprecation of the legacy API. In the past couple of weeks we have made more aggressive moves to get rid of it, removing the legacy API documentation from man.sr.ht and disabling some features which are not still being used by anyone. I have some flashy end-user-facing features coming up soon as well &ndash; but let&rsquo;s make it a surprise.</p> <h1 id="conrads-updates">Conrad&rsquo;s updates</h1> <p>Before I start, I&rsquo;ll let you in on a little secret. Like many infrastructure engineers, I have evolved to have two questionable superpowers. One is stumbling across very weird issues that take days to debug only to be fixed eventually by a single-line code change. The second is to perform major refactorings, often coördinated across multiple codebases, resulting in plenty of code changes but no discernable difference in functionality of any of the touched components. Both these superpowers are greatly under-appreciated by managers (&ldquo;Last week I stared at packet traces, then disabled a single sysctl on all servers, that&rsquo;s all, really&hellip;&rdquo;). Fortunately, there are no managers at SourceHut, because I have plenty of the second category for you!</p> <p>All our Python packages are finally PEP440-compliant! 🎉 This took <em>so</em> long and added <em>zero</em> value for our users, yet it was inevitable. And it did have the pleasant side effect of finally unbreaking builds for submitted patches again.</p> <p>Another epic, but mostly invisible undertaking was the recent &ldquo;shared asset refactoring&rdquo;. This one, however, brought significant quality-of-life improvements for developers. It also drastically changed the process for setting up a dev environment. The <a href="https://man.sr.ht/hacking.md#install-shared-assets">generic instructions</a> have already been updated, but I am also working on a more detailed write-up. Piggy-backing on this big change we also renamed all executables to have a consistent naming scheme, which should help developers and instance admins alike.</p> <p>And yet more from the &ldquo;big changes you didn&rsquo;t notice&rdquo; department: we finally consolidated all SSH key handling in meta.sr.ht. Previously, services requiring SSH access (like git and hg) would have their own copy of the SSH key table, which was prone to stale data and other inconsistencies. This unlocked the removal of various chunks of legacy API surface, with even more cleanup yet to come. Specifically, the entire SSH dispatching - which currently has very similar implementations in various services - will get a face-lift, improving code re-use and reducing complexity.</p> <p>Okay, I&rsquo;ll give you a break - here is something very tangible: in lists.sr.ht, we removed the instance-wide configuration that blocks emails with HTML parts, <a href="https://git.sr.ht/~sircmpwn/lists.sr.ht/commit/d2470931">putting list owners in full control</a> to make their own choices about blocking such parts.</p> <p>As for what&rsquo;s cooking right now: besides the above-mentioned SSH dispatching I am working on refactoring log file locations for all services and providing log rotation policies with our packages. We are also preparing to extend our Ceph cluster, and we&rsquo;ll have to retry botched Alpine upgrades on two hosts which had an unfortunate combination of packages installed, triggering some <a href="https://gitlab.alpinelinux.org/alpine/aports/-/issues/16907">very sneaky breakage</a> in Alpine&rsquo;s ceph packages. So, you know, lot&rsquo;s of epic stuff that no one will notice. Unless it breaks something.</p> What's cooking on SourceHut? September 2024 https://sourcehut.org/blog/2024-09-16-whats-cooking-september-2024/ Mon, 16 Sep 2024 00:00:00 +0000 https://sourcehut.org/blog/2024-09-16-whats-cooking-september-2024/ <p>Hello everyone! It has been <a href="https://sourcehut.org/blog/2022-10-18-whats-cooking-october-2022/">some time</a> since we last wrote a &ldquo;What&rsquo;s cooking&rdquo; for you. We&rsquo;d like to resume this tradition as of this September. We haven&rsquo;t been totally radio silent &ndash; you can get caught up on what&rsquo;s been happening over these past two years <a href="https://sourcehut.org/blog">reading the blog archives</a> &ndash; but we&rsquo;ll be resuming monthly updates to keep you more informed about the minutiae of our operations. We&rsquo;ll be presenting our updates from the perspective of each of our staff members, Drew and Conrad.</p> <h2 id="drews-updates">Drew&rsquo;s updates</h2> <p>Hi folks! As promised in our update in <a href="https://sourcehut.org/blog/2024-06-04-status-and-plans/">June</a>, I have mostly been working on paying down our tech debt recently, in addition to shouldering a fair bit of ongoing maintenance, minor bug fixing, and so on. At the moment I am working on the steps which will unblock our legacy REST API in favor of the GraphQL API.</p> <p>The main focus of my work in this area is on refactoring internal users of our legacy API (e.g. the project hub queries git for repository details via REST). I have mostly updated the project hub accordingly, and I&rsquo;m taking a small diversion to buff up our <a href="https://sourcehut.org/blog/2021-08-25-graphql-native-webhooks/">GraphQL-native webhooks</a> so that I can migrate the project hub away from using legacy webhooks. For this purpose I am developing and rolling out a more sophisticated approach to <a href="https://git-scm.com/docs/githooks/2.27.0">git hooks</a> which allows users to prepare GraphQL queries that are executed during a git push, whose payloads are delivered to an arbitrary user-defined server. For now these are done asynchronously and cannot affect the outcome of git push, but I will be expanding it to allow users to accept or reject git pushes based on their own policies, such as enforcing an OWNERS file.</p> <p>Following this work I will continue refactoring internal users of the legacy API, and in this process I plan on aggressively refactoring out legacy code in our shared Python codebase, core.sr.ht, which is the most important user of the legacy API right now. Once a bow is put on all of this work, I will start planning the deprecation of the legacy API and reach out to contemporary third-party users of the legacy API to assist with a migration plan for their use-cases. The next big tech-debt priorities after this will be the removal of Celery and SQLAlchemy from our dependency tree.</p> <p>Aside from tech debt, the next big user-facing features I plan to address are the billing overhaul and improvements to the lists.sr.ht code review workflows. The tech debt I have on my plate is pretty substantial though, so we may not have any updates on this front by next month.</p> <h2 id="conrads-updates">Conrad&rsquo;s updates</h2> <p>You came for the fun, now you get to stay for the infrastructure updates (mostly)! I&rsquo;ve been hard at work following up on the plans <a href="https://sourcehut.org/blog/2024-06-12-infrastructure-updates/">outlined earlier</a>.</p> <p>Let&rsquo;s start with the elephant in the room: we successfully migrated our DNS infrastructure back in-house. While I think this is great, it had the unfortunate side-effect of it being unavailable for a brief period last Friday, due to an upstream ISP issue. But let&rsquo;s be clear: even if DNS would have continued to work, all servers were unavailable anyways. That&rsquo;s a trade-off you make when you&rsquo;d rather own your infrastructure than operating at &ldquo;planet scale&rdquo;, and we continue to be proud believers in this approach.</p> <p>We have also completed the separation of the Kubernetes cluster from the VM hosts. See the <a href="https://sourcehut.org/blog/2024-06-12-infrastructure-updates/">previous post</a> for details, but this finally allows us to migrate actual workloads to Kubernetes. The first one is our new Prometheus setup, which you can already see at <a href="https://metrics.srht.network">metrics.srht.network</a>. It has already taken over the production monitoring and alerting. There are just a few more bits and pieces that need to be moved over before I&rsquo;ll be able to shut down the first VM for good: <code>metrics.sr.ht</code>.</p> <p>I&rsquo;ve also performed several upgrades of Kubernetes itself and am currently preparing an Alpine upgrade on the bare metal hosts. Once all that is completed, the fun part will start: moving actual services &ndash; or parts thereof &ndash; into the cluster.</p> <p>On the application layer, I am still pursuing the busywork of making our Python packages PEP440-compliant. I have also been on a mission to address some resource leakage in soju, unfortunately with mixed success. We&rsquo;re slowly getting there, but the turn-around time is rather high, as we cannot constantly annoy network operators (and users) with reboots of the bouncer.</p> <p>Once the major infrastructure tasks outlined above are complete, I hope to spend more time on actual application code again. But the Alpine upgrades, especially the one involving our main storage host, might still keep me busy for a while.</p> The European NGI fund must be renewed https://sourcehut.org/blog/2024-07-18-ngi-must-be-renewed/ Thu, 18 Jul 2024 00:00:00 +0000 https://sourcehut.org/blog/2024-07-18-ngi-must-be-renewed/ <p>In 2022, <a href="https://sourcehut.org/blog/2022-01-10-nlnet-graphql-funding/">SourceHut was selected</a> for funding from the European Union&rsquo;s NGI fund. This fund has been used to provide small grants to many free software projects since 2020, and the impact of these grants has been enormous. In SourceHut&rsquo;s case, the grant is directly to thank for our comprehensive GraphQL APIs, which both underpins SourceHut&rsquo;s internal communication needs and makes this platform possible, and are depended on by our users to achieve our goals of personal data ownership and platform independence.</p> <p>Thanks to NGI funding, Europe has been the spearhead of innovation in free software over the past four years. There are hundreds of free software projects which can thank this fund for their success, projects which would not have been possible without it &ndash; and because of this fund, the technology they provide is available in the commons, for the benefit of all. The NGI fund has enormously strengthened Europe&rsquo;s technology stance and drawn the continent out as one of the best, if not the best, places to innovate in free software and support internet and technology resilience, security, sovereignty, and innovation. These goals cannot be achieved any other way &ndash; many of the projects that benefit from NGI funding cannot reasonably find their way without a funding source like this.</p> <p>Moreover, the fund has been shown to be an incredibly efficient way of spending towards innovation. The NGI grants punch well above their weight. We have seen NGI grants in the tens of thousands accomplish goals which the commercial sector demands tens of millions in investments to achieve, and the NGI-funding outcomes are placed into the commons and support the public interest &ndash; something private funding cannot do. I can think of no better example of efficient public spending on innovation than the NGI fund: the returns on a small NGI investment are huge.</p> <p>So, it was to our dismay to learn that the European Commission has not included the NGI program in its Horizon Europe working draft for funding programs in 2025. SourceHut joins <a href="https://pad.public.cat/lettre-NCP-NGI#">an open letter</a> to the European Commission calling for them to reconsider. If anything, it is not only important but urgent that the commission expands the NGI program &ndash; not shut it down. The NGI program is a cornerstone of Europe&rsquo;s future in technology and innovation, and it embodies the European commmunity&rsquo;s values in a way we must honor and uphold.</p> <p>We urge the commission to reconsider.</p> <p>&ndash; SourceHut</p> Update on our infrastructure plans https://sourcehut.org/blog/2024-06-12-infrastructure-updates/ Wed, 12 Jun 2024 00:00:00 +0000 https://sourcehut.org/blog/2024-06-12-infrastructure-updates/ <p>Now that Drew has provided <a href="https://sourcehut.org/blog/2024-06-04-status-and-plans/">an update</a> on the general state of SourceHut, I would like to follow up with one focusing on our infrastructure. Much has happened under the hood, a lot has <em>not</em> happened, and plans come and go as reality changes its mind every now and then. So, let&rsquo;s take a quick look at where we are right now, what our plans are, and how we hope to get there.</p> <p>First and foremost, let me state the TL;DR: our grand plan has not changed, and we are still planning on moving most services to Kubernetes. But to talk about why that&rsquo;s taking so long, how we are preparing for this, and what this means for folks running their own instances, I need to set the stage a little bit.</p> <h2 id="quick-recap">Quick recap</h2> <p>As Drew already mentioned, we hastily migrated all our services to our research facilities in Amsterdam during the <a href="https://sourcehut.org/blog/2024-01-19-outage-post-mortem/">recent DDoS attack</a>. This was a desperate measure, and while it actually had <em>some</em> benefits, it came mostly with drawbacks.</p> <p>Our research facilities at the time consisted of a &ldquo;grand&rdquo; total of three servers. They provided two things: a Ceph cluster and a Kubernetes cluster. The Kubernetes setup was far from ready for production. But in a stroke of luck it had been just recently that I had upgraded our Ceph cluster from the few spinning disks we used for toying around to a significant number of SSDs that were intended for production use. And so, we made the decision to migrate our storage to the new Ceph cluster, but keep running the services in VMs like we did before.</p> <p>The research hardware is quite powerful, but it was still clear we would need more. It is also close to impossible to provide any level of redundancy with just three servers. We decided to rent two physical servers as build runners, an intensive and at times unpredictable workload. We also decided to keep our DNS in Digital Ocean, where we had moved it to get it out of the DDoS blast radius. These setups remain in place to this day.</p> <h2 id="the-good-the-bad-and-the-ugly">The good, the bad, and the ugly</h2> <p>The migration was done under pretty intense pressure, as all our services were unavailable. Once the dust had settled after the DDoS, it was time to inspect the result more closely.</p> <p>The obviously good outcome: it worked! We had managed to bring all of SourceHut back up in Amsterdam and were able to restore service. That was quite a feat. Another outcome I was initially very excited about was data locality. All of a sudden, there was a chance to bring up a service in Kubernetes and let it handle some production traffic without worrying about transatlantic latency for internal requests. We&rsquo;ll see how that turned out in a minute, though.</p> <p>The bad part was - at least initially - the Ceph cluster. While we had the storage capacity we needed, there had not been any performance testing yet. So this unfortunately happened in production, with the predictable, occasional hiccup. But by now, things have settled down and it seems the cluster can handle the load just fine. The object storage still feels a little less performant than before, but bearable. We&rsquo;ll continue to tweak things, and hope things will get even better once we start using the advanced features of Ceph for horizontally scaling our services.</p> <p>Since most time was spent tending to the Ceph cluster, it took a while until the ugly part dawned on me. In our old setup, every service was running in a VM, and the hosts that ran the VMs did nothing but that. When we frantically moved all that over as-was, we ended up in a silly situation. All the VMs were using <em>macvtap</em> interfaces, which are very easy and convenient to set up, but have one very annoying quirk: they can talk to anything on the network, <a href="https://wiki.libvirt.org/TroubleshootMacvtapHostFail.html">except the very host they run on</a>.</p> <p>As you can imagine, with just three servers running a Ceph cluster and a Kubernetes cluster, using any of those <em>only</em> for running VMs was not an option. And so, a service brought up in Kubernetes was unable to talk to VMs that happened to run on the same host that it was scheduled on.</p> <p>I spent many days thinking about workarounds, but they would have all been extremely foolish. We had very little headroom to shuffle things around. In the end, I decided that the only sane option to run anything in Kubernetes was to get rid of the macvtap interfaces, switching to a proper bridge setup. But this would have required bringing down the entire host network, which would have had a huge impact on many services. I made plans, but hesitated with the actual execution. The situation was extremely frustrating.</p> <h2 id="the-plot-twist">The plot twist</h2> <p>It was just then, that we received an offer that would change everything. An anonymous saint (&lt;3) gifted us eight servers. They are of the kind that is considered old in some places, but they are perfect for us. At this point, I decided to just postpone running anything in Kubernetes. These servers would allow us to move things around carefully and straighten out the kinks without interrupting service.</p> <p>It took a few weeks of preparation and planning, but the servers are now installed and operational. So, finally, we are able to move forward. And this is how we, at last, get to the interesting part.</p> <h2 id="whats-next">What&rsquo;s next?</h2> <p>The first task will be to bring our DNS back in-house. This is needed to bring back some features we need for Kubernetes, like DNS dynamic updates for completing ACME challenges.</p> <p>Then, we will physically separate the Kubernetes cluster and the VM hosts, so everything can properly talk to each other. This will finally unlock experimenting with production services in Kubernetes.</p> <p>On the topic of Kubernetes, I know a lot of people are excited about that, but I feel a word of caution is in order. While it will facilitate some aspects of running an instance, I am not sure it will be an &ldquo;off-the-shelf&rdquo; solution anytime soon. For example, some of our services will rely on CephFS for horizontal scaling. This can probably be reproduced even at small scale with Rook, but we currently do not use it, and I am not sure if we ever will.</p> <p>Another issue is that SourceHut in its entirety includes several services that are not a great match for Kubernetes in the first place. Kubernetes is first and foremost designed for HTTP requests. But we have multiple services that require for example SSH, which is notoriously hard to load-balance, and does not have any equivalent of SNI. Our candidate setup for that involves dedicated IPs (external load balancers), which are usually a platform-specific feature. What works for us, may not work for you.</p> <p>That said, I think solutions will pop up, and it makes sense to cross that bridge when we get there. One reason for the lack of tangible Kubernetes services so far was that we believe in solving the hard problems first. We have had a working prototype of build workers running, and proofs of concept for SSH routing. But knowing that it is all possible, priorities have shifted slightly. We will keep the rented build workers for a little longer, until we are confident in our infrastructure setup. We&rsquo;d also like to do some refactoring of the builds.sr.ht codebase before moving those to Kubernetes. So, once the above steps are completed, the time may have truly come to start testing some of the &ldquo;simpler&rdquo; services in Kubernetes. That is, of course, unless reality changes its mind again&hellip;</p> <h2 id="thank-you-for-your-patience">Thank you for your patience</h2> <p>I hope this update answers some of the questions I occasionally see on IRC. It&rsquo;s always hard to give brief answers to seemingly simple questions when the reality is such a complex mess. That said, I&rsquo;ll do my best to monitor both #sr.ht and the <a href="mailto:~sircmpwn/[email protected]">sr.ht-discuss list</a>. But even if I don&rsquo;t respond, I am quite hopeful you will see answers soon.</p> <p>Cheers!</p> The state of SourceHut and our plans for the future https://sourcehut.org/blog/2024-06-04-status-and-plans/ Tue, 04 Jun 2024 00:00:00 +0000 https://sourcehut.org/blog/2024-06-04-status-and-plans/ <p>Good morning! It&rsquo;s been a tough year for SourceHut and I know many of our users are waiting to hear from us. Our last update was the <a href="https://sourcehut.org/blog/2024-01-19-outage-post-mortem/?ref=footer">post-mortem</a> following the DDoS attack we sustained in January, and we have some additional news following this update as well as plans for the coming months to share.</p> <p>I apologise for the reduced communication as of late. We are a small team dealing with a lot of big problems, and between keeping the lights on, dealing with issues as they arise, and leaving time for us to rest and spend time with our families, there has not been as much room for keeping you up to date. Nevertheless, our ship sails on, things have quieted down now, and we have an opportunity to get you filled in today.</p> <h2 id="so-far-in-2024">So far in 2024</h2> <p>I&rsquo;ll be honest with you &ndash; it hasn&rsquo;t been great. We are not facing an existential crisis &ndash; we have extensive disaster planning for many scenarios we might face, and our situation is well within the scope of our planning &ndash; but nevertheless it has been a challenge.</p> <p>As you know, during the DDoS we suffered a total network outage on our primary datacenter and had to perform an emergency overnight migration of all of our infrastructure to our research installation in our datacenter lease in Amsterdam. Our infrastructure became stable following this intervention, but we have been operating at a reduced capacity since &ndash; we are running SourceHut on infrastructure provisioned for research, not production. Currently we are supplementing our owned-hardware compute with a lease from OVH for build server cycles.</p> <p>Following the failure of our primary datacenter, we arranged to have our equipment shipped overseas to our research datacenter, so that we could install this equipment and restore our infrastructure to its full production capacity on SourceHut-owned hardware. At our now-deprecated site we had ten servers totalling an investment of about $50,000 USD. Some of this equipment was at the end of its operational life and was disposed of accordingly, but we arranged to have five servers shipped to Amsterdam. However, all five servers were lost in the mail. These parcels were insured with the shipping provider, but we have been unable to reach the provider for any information regarding the status of the parcels or any resources for filing an insurance claim. After several months of attempts, we have ultimately had to write these servers off.</p> <p>Moreover, we are facing some financial issues. The loss of this equipment represented a significant lost investment, and the shipping costs were substantial. Additionally, we are working with a tax issue in which we were over-taxed by about $20,000; we filed an appeal months ago but that money is tied up for the time being and the tax authorities have sent us timely notices every 60 days informing us that they require an additional 60 days to process the issue. We still have an entirely sustainable financial situation, but we lack access to the capital we would ideally be using to build out our infrastructure and address other needs for growth.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p> <p>You may have heard that we also had to part ways with one of our staff members recently. This reduces our headcount to two. For the time being we will not be hiring a replacement, but our near-future plans are achievable with our current headcount. Though we usually aim for transparency to the maximum extent possible, we will not be sharing further details about this departure, as a matter of reasonable privacy.</p> <p>As you can imagine, it has been a stressful time for us. However, I wish to stress that everything we&rsquo;ve been dealing with is planned for in our models, both technical and financial. There is no existential threat to SourceHut. Nevertheless, we are grateful for your patience and support.</p> <p>There is some good news to share &ndash; some old colleagues of ours generously provided us with eight servers to shore up our capacity in the new datacenter and mitigate some of the losses from the bungled overseas shipments. These were installed last week, and we are provisioning them now and preparing to bring them into service. We also did a marvelous job at upgrading our research installation to production readiness, polishing it into a much more robust system over the weeks and months following the disastrous DDoS attack.</p> <p>Also, as a happy side-effect of our surprise move to Amsterdam, SourceHut&rsquo;s datacenter installation is now entirely powered by renewable energy sources. We have also finally rolled out IPv6 support for most SourceHut services as part of our migration!</p> <h2 id="in-the-months-to-come">In the months to come</h2> <p>It follows from our story that we have been focusing on two things this year: provisioning and managing our infrastructure and getting as much rest as possible. Our situation has calmed down, and while we still have a lot of loose ends to attend to I&rsquo;m happy to say that we&rsquo;re resuming a sense of normalcy here and preparing to resume our work on the features you need.</p> <p>Our plan for the coming months involves the following objectives:</p> <ol> <li>Implementing Kubernetes for managing our infrastructure</li> <li>Paying down tech debt in the codebase</li> <li>Fleshing out the remaining &ldquo;alpha&rdquo; feature goals</li> </ol> <p>Conrad will continue leading the efforts to k8s-ize our production infrastructure. Our AMS datacenter installation was provisioned with k8s in mind, rather than with the parameters we used for our earlier libvirt-based infrastructure. As a temporary measure, we have bolted our libvirt approach onto the servers we have installed here, but we are planning on gradually migrating our deployment to a k8s-based approach which is better suited to the infrastructure we have provisioned, as well as (hopefully) being more robust and scalable, meeting the original objectives of our k8s research. We have migrated our large persistent storage system to Ceph, and are working on moving our API and web services into k8s one at a time.</p> <p>Then there is the matter of &ldquo;tech debt&rdquo;. SourceHut&rsquo;s codebase traces its lineage directly to our early prototypes, and there are many design choices and bright ideas which are not so bright in hindsight. We had initially planned to work on paying down tech debt between the &ldquo;beta&rdquo; and &ldquo;full production&rdquo; phases of SourceHut&rsquo;s development lifecycle, but these areas are causing us enough headache that we have made the decision to spend some time reducing our tech debt today. In particular, we have the following goals:</p> <ul> <li>Remove Celery from our architecture</li> <li>Remove SQLAlchemy from our codebase (and route web frontends through the GraphQL APIs instead)</li> <li>Deprecate internal users of the legacy APIs and webhooks (and redesign services with a single source of truth for each data store)</li> <li>Refactor user management in core.sr.ht, in particular to get rid of the old &ldquo;delegated OAuth&rdquo; subsystem</li> </ul> <p>Following this we intend to finish up the remaining &ldquo;alpha&rdquo; feature goals, which includes the following:</p> <ul> <li>Overhaul our billing system and migrate to a new payment processor. This will include support for paying in more currencies, an improved invoicing system, and support for many more payment methods, such as iDEAL and European bank transfers.</li> <li>Overhaul and expand the web patch contribution and code review workflows.</li> <li>Implement user organizations and shared resources.</li> </ul> <p>We have further plans over the long-term: reducing the use of Python in our codebase, overhauling builds.sr.ht and expanding its features, improvements to man.sr.ht, and so on, but for now the goals enumerated above are chief among our priorities.</p> <h2 id="thanks-for-sticking-with-us">Thanks for sticking with us</h2> <p>Thank you for your continued support and patience while we get our house back into order. We hope you are continuing to enjoy SourceHut for your needs and the needs of your projects.</p> <p>If you have any questions about the events of this year, or our plans for the future, or anything else &ndash; feel free to reach out. You can reach all of us in private by <a href="mailto:~sircmpwn/[email protected]">emailing support</a>, or the community in public at <a href="mailto:~sircmpwn/[email protected]">sr.ht-discuss</a>, or you can reach me (Drew) directly via <a href="mailto:[email protected]">[email protected]</a>. We&rsquo;re also around on IRC &ndash; #sr.ht on Libera Chat.</p> <p>Take care!</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>If you have the financial means and wish to help, this would be a great time to consider upgrading your paid subscription &ndash; though it is by no means necessary for us to keep things running.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> SourceHut network outage post-mortem https://sourcehut.org/blog/2024-01-19-outage-post-mortem/ Fri, 19 Jan 2024 00:00:00 +0000 https://sourcehut.org/blog/2024-01-19-outage-post-mortem/ <p>It&rsquo;s been a busy couple of weeks here at SourceHut. At the time of writing, we have restored SourceHut to full service following an unprecedented 170 hour outage, and while we still have numerous kinks to sort out following an unscheduled emergency migration of all services across an ocean, all services are now fully operational.</p> <p>Allow me to open this post-mortem by extending my deepest apologies to the SourceHut community for this interruption in service. This outcome was unacceptable: we failed you, and I am sorry. We know that you depend on SourceHut to be reliable, and you trust us to make sure that you can always depend on our services to be there for your projects. We value this trust profoundly, and we will strive to prevent a situation like the one we faced last week from recurring. The Internet can be a fragile place, and we will do what we can to re-enforce it.</p> <p>Here&rsquo;s what happened, what we did about it, how we&rsquo;re making things right, and what we&rsquo;re doing to ensure it does not happen again.</p> <h2 id="background">Background</h2> <p>SourceHut runs on servers owned and provisioned by SourceHut, installed in colocation facilities at three datacenters, respectively codenamed PHL, AMS, and FRE. PHL was our primary datacenter, FRE was used for off-site backups, and AMS was a research installation intended for a future migration of our production infrastructure in PHL and next-generation deployment of SourceHut intended to scale into the indefinite future.</p> <p>We have been setting up an installation in AMS for researching a future infrastructure migration to the EU and means of increasing our resilience and redundancy, which we had planned to gradually roll out with minimal disruption to user service over the course of at least a year. In the end, we rolled it out with maximum disruption to user service in 7 days. The AMS datacenter installation was provisioned according to a projected research workload with an eye towards expanding it to support a full SourceHut installation in the future; at the time of the incident it was provisioned at a scale appropriate for running <em>most</em> of a SourceHut installation.</p> <p>Our FRE datacenter is used for off-site backups. We maintain a Postgres standby which is replicated in real-time and is usually up-to-date within seconds of production, as well as daily backups of large data silos such as git.sr.ht. We have a comprehensive monitoring system in place which, among monitoring other systems, keeps track of these backups and notifies us when their metrics fall outside of our window; for instance we receive an alarm if the database replica is more than 5 minutes behind production or if large storage backups exceed 48 hours.</p> <p>We maintain a comprehensive set of operational plans for responding to various incidents which may arise, ranging from hard drive failure up to and including the complete failure of a datacenter, which proved to be important when addressing this scenario. We also have standard response times for responding to various tolerances being exceeded which are designed to minimize user impact; for instance we configure the storage utilization alarms with sufficient lead time to provision additional storage.</p> <p>The complete failure of a datacenter is the most challenging situation we have prepared for, and it is the situation with which we were ultimately faced.</p> <h2 id="the-incident">The incident</h2> <p>At around 06:00 UTC on January 10th, a layer 3 distributed denial-of-service (DDoS) attack began to target SourceHut&rsquo;s PHL infrastructure. We routinely deal with and mitigate application layer (layer 7) DDoS attacks, however, a layer 3 attack takes place at a lower level and is not within our ability to mitigate without the assistance of our network provider. Starting from about 06:00, our monitoring systems noticed that something was wrong and raised the alarm, and we started investigating the issue shortly thereafter. However, before we could get a handle on the situation, our access to the PHL network completely disappeared at around 09:00 UTC.</p> <p><img src="https://sourcehut.org/january-outage.png" alt="Screenshot of our monitoring system detecting problems"></p> <div class="alert alert-info"> We never received any kind of ransom note or other communication from the attacker. We do not know who was behind the attack, nor their motivations, and likely never will. We know that they targeted SourceHut specifically, and that they followed us as we worked on mitigations, directing their attack at new infrastructure as it was being set up.<br /><br /> In this post-mortem we are going to focus on the impact on our network and the steps we took to restore service, rather than going into what we know of the attack and the details of our mitigations, both for information security reasons and to avoid lending legitimacy to a bad actor. In the end, the response to the attack from our upstream network in PHL did more damage to our infrastructure than anything else. </div> <p>We rent network service in PHL from our colocation provider, who provisions a subnet out of their AS and routes it through Cogent and Level 3. In response to the attack, Cogent announced null routes for our downstream AS, causing our PHL network to become unreachable both for SourceHut staff and the general public.</p> <p>We attempted to contact our colocation provider at this point, but we were unsuccessful. Our provider in PHL has been acquired twice over the past couple of years, and it seems that the ticketing portal we were used to paging them with had been deprecated and our account had not been migrated to the new system. We were unable to reach them until their normal office hours opened at 14:00 UTC. Our provider restored our access to the priority ticketing system and began to investigate the issue. Eventually they were able to convince Cogent to reduce the null route from our entire /24 to a narrower /32 focusing on the specific IP address being targeted by the DDoS. As a result, service was mostly restored by 18:00 UTC.</p> <p>At about 06:30 UTC the following morning, the DDoS escalated and broadened its targets to include other parts of our PHL subnet. In response, our colocation provider null routed our subnet once again. This subnet has been unreachable ever since.</p> <p>At 09:00 UTC, I made the call to perform an emergency migration to AMS and restore from backups. We began urgently planning the scope of this work, making an assessment of our backups and the Amsterdam installation&rsquo;s capacity to host a fully functional SourceHut installation, and planning the work that needed to be done. We verified the health of FRE and AMS and our backup systems, finding that our standby database was less than 30 seconds out of date with production and that our large storage backups were no more than 12 hours old. We found that AMS was in good health and we touched up a few research systems (e.g. Ceph) to bring them to production readiness.</p> <p>What essentially followed was creating a new installation of SourceHut from scratch, importing production data, testing and verifying the installation, and bringing it online for user service on a new DDoS-resistant network. This involved hundreds of small tasks that we planned out and distributed among ourselves and executed as urgently as possible, the full details are too involved to repeat here. However, the general plan had the following broad strokes:</p> <ul> <li>Migrate to external DNS</li> <li>Bring up a new primary database</li> <li>Restore backups from FRE to AMS</li> <li>Migrate object storage from PHL to AMS</li> <li>Bring up database-only services, such as meta, todo, project hub</li> <li>Bring up large storage services as backup restores finish</li> <li>Manually apply the diff between production data and the last backups</li> <li>Provisioning a new mail system and configuring mail services for it</li> <li>Identify a suitable DDoS-resistant network to bring us into general service</li> <li>Provision servers to backfill AMS capacity to production readiness</li> <li>Test the new systems and bring them into general service</li> </ul> <p>All of this work happened in parallel and had cross-dependencies, so from here on out we will omit some timestamps.</p> <p><strong>Network solutions</strong></p> <p>The selection of a suitable network to bring into service that would not immediately collapse as the DDoS attack followed us presented some challenges. First, this was a layer 3 attack, which can essentially only be mitigated by having more bandwidth than the attacker and/or by filtering traffic at a location suitably far upstream. Furthermore, many DDoS protection systems only operate at the application layer, namely for the web as the application in question, whereas SourceHut has user-facing services through not only HTTPS but also SSH, SMTP, and IRC; moreover we strongly prefer to utilize end-to-end encryption on all traffic and terminate it on SourceHut-operated infrastructure.</p> <p>We initially researched a number of solutions, and spoke to Cloudflare in particular due to their ability to provide a rapid response to ongoing incidents. However, given our complex requirements, Cloudflare quoted us a figure which was not attainable within our financial means as a small company. Other options we researched (though we did not seek additional quotes) had similar economical constraints. However, we found that OVH&rsquo;s anti-DDoS protections were likely suitable: they are effective, and their cost is amortized across all OVH users, and therefore of marginal cost to us. To this end the network solution we deployed involved setting up an OVH box to NAT traffic through OVH&rsquo;s DDoS-resistant network and direct it to our (secret) production subnet in AMS; this met our needs for end-to-end encryption as well as service over arbitrary TCP protocols.</p> <p>We also got in contact with our network operator in AMS and explained the situation to them. We found some solutions to mitigate attacks directed at AMS but we will not disclose details regarding the AMS network for reasons of information security.</p> <p>We made some mistakes throughout the operation, rsyncs done incorrectly, networks misconfigured, and so on. One particularly amusing mis-step occurred when we configured the NAT through OVH: we naively NAT&rsquo;d all traffic through to AMS, and when the attack resumed targeting our OVH infrastructure, the inbound DDoS was briefly forwarded to AMS before OVH&rsquo;s mitigations kicked in, which made our brand new OVH account look like the source of an <em>outgoing</em> DDoS, with predicable consequences that took some work to resolve with OVH.</p> <p>Following our initial quote from Cloudflare, we understand that some Cloudflare employees undertook a grassroots effort internally to convince the leadership to sponsor our needs, and eventually Cloudflare came back to us with an offer to sponsor our services for us free of charge. This was a very generous offer for which we are very appreciative; in the end we did not take them up on it as we had made substantial inroads towards an alternative solution by that time. I have had my reservations about Cloudflare in the past, but they were there for us in a time of need and I am grateful for that.</p> <p>On January 12th, our network provider in PHL agreed to provision a temporary subnet through which we could receive out-of-band access to our PHL servers. We were able to speed up the provisioning of replacement infrastructure thanks to this being made available.</p> <p><strong>Provisioning services</strong></p> <p>Efforts to restore individual SourceHut services came with a variety of challenges. Some of them were fairly straightforward; services like paste and the project hub depend only on a working SQL server and once we had that in place we were able to restore them to service at about 19:00 UTC on January 11th.</p> <p>git.sr.ht and hg.sr.ht had special considerations due to the large amount of data they were responsible for. We restored them from backups to read-only service based on somewhat stale data by 20:00 UTC, and restored to full read/write service by 11:00 UTC on January 13th. We also did our best with hg.sr.ht, but it is community maintained and restoring service was delayed until we could get the community maintainer, Ludovic Chabant, online to help; it was fully restored at 08:20 UTC on January 15th.</p> <p>pages.sr.ht also presented unique challenges due to its use of an S3-compatible object storage solution, which we discovered was not considered in our off-site backups. However, it was a priority to restore service to bring online the numerous personal and project websites which depend on pages.sr.ht. Migrating object storage from PHL to AMS is a slow procedure which is still underway now, we are running pages through an out-of-band link to PHL which comes with some performance limitations but provides service while the slower migration process is underway in the background. Pages also had to be moved to a new subnet and IP address, which posed a problem for users who configured their apex records to point directly to the PHL subnet; we have now emailed affected users with instructions for manual intervention.</p> <p>chat.sr.ht also poses some unique constraints due to its approach to networking; for a number of reasons we implement outbound IRC connections on a unique IPv6 address per-user. Preparing the requisite network infrastructure and bringing it online required special considerations and as a consequence chat.sr.ht was the last service to be restored to full operation at 10:30 UTC on January 17th.</p> <p>builds.sr.ht also required some extra considerations due to the fact that our research installation in AMS was under-provisioned for its compute requirements. Currently we are running build workers on dedicated baremetal OVH servers and we are planning to bring build service back onto SourceHut-operated infrastructure once we are able to ship our builds-oriented compute servers from PHL to AMS in the coming weeks. We began accepting build jobs again at 18:00 UTC on January 16th.</p> <p>All told, we began restoring partial service availability on the afternoon of January 12th, and gradually brought up services over the following days until full service was restored on the morning of January 17th. Following the complete restoration of service we credited all paying SourceHut users with 7 days of free service.</p> <h2 id="whats-next">What&rsquo;s next</h2> <p>We have completed all user-facing steps required to restore SourceHut to full service. However, we have numerous tasks to perform internally to put the finishing touches on the new installation and to clean up workarounds and hacks put in place to restore service as quickly as possible. We have an internal bugtracker with about 60 post-incident tasks to be completed, some of which are finished and others which are still underway: for instance, we have provisioned a new standby database, configured backups from AMS =&gt; FRE, and we are working on installing a new monitoring system.</p> <p>We are also deprecating our PHL datacenter installation entirely. We still cannot reach the network there, and the operator has egregiously exceeded their SLA with us. We will pack up the servers in PHL and ship them to AMS to supplement capacity there.</p> <p>Ironically, this emergency migration allowed us to quickly achieve many of the long-term goals we had in mind for migrating to the EU. We are now running almost entirely on European infrastructure and we quickly finished bringing many of our plans to ensure future scalability and reliability of SourceHut infrastructure to production readiness. We had planned to do these upgrades without user impact, but, well, alas.</p> <p>Part of the work involved in setting up the AMS datacenter installation was geared towards increasing resilience, reliability, and redundancy, and reducing the impact of attacks and outages of this nature. SourceHut is still in an &ldquo;alpha&rdquo; state, and though we have built a platform that is sophisticated and depended on by numerous free software projects, that comes with some caveats. This incident exposed one such caveat, a shortcoming that we were aware of and actively working on improving, but which was exploited before we could complete our goals for redundancy and resilience. Our definition of production readiness, our &ldquo;definition of done&rdquo; for the alpha, includes building infrastructure that prevents this kind of outcome. We have made unexpectedly urgent inroads on these milestones, and we will continue to build out these solutions as part of our work to bring SourceHut from alpha to beta to production.</p> <p>In the service of this work, we have been researching a solution for running SourceHut in an on-premise Kubernetes cluster (cue gasp from the audience). The migration to AMS did not involve a migration to Kubernetes, but it did put us in a better position to expedite that work. We intend to utilize this work to reduce user-impacting downtime during internal maintenance, such as when scaling up our infrastructure or upgrading software, but also to improve our resistance to events such as the one that transpired this week. Once we have completed an implementation of this solution, we will be planning out a secondary production-ready datacenter which we can load balance against and which can step up to take on full service in the event of a datacenter outage, as well as making it easier to conduct the procedures that we employed this week to stand up SourceHut from scratch in a new datacenter should the need ever arise again.</p> <p>As unfortunate as these events were, we welcome opportunities to stress-test our emergency procedures; we found them to be compatible with our objectives for the alpha and we learned a lot of ways to improve our reliability further for the future. We are going to continue working on our post-incident tasks, building up our infrastructure&rsquo;s resilience, reliability, and scalability as planned. Once we address the high-priority tasks, though, our first order of business in the immediate future will be to get some rest.</p> <h2 id="acknowledgements">Acknowledgements</h2> <p>I&rsquo;d to acknowledge those who helped us in this difficult time. Of course, I extend my thanks to the rest of the staff, Simon and Conrad, whose long hours of work ensured we could restore service for our customers as quickly as possible. I would also like to thank the staff and network operators at our various datacenter locations, for their role in facilitating our needs in the rapid bring-up of new infrastructure. Thanks especially to the community members who sent us their words of support and kindness, and offers of aid, via email, Mastodon, on IRC, and so on.</p> <p>Thanks are also due to our peer in the free-software-forge space, Codeberg. They hosted our status page prior to the incident, and likely faced their own DDoS attack in retaliation for the services they provided to us. We shared information across our teams extensively and their communication and relationship with SourceHut has always been superb.</p> <p>I&rsquo;d also like to thank the team at Cloudflare; though we did not accept your generous offer we were appreciative that you were there for us in a time of need.</p> <p>On a personal note, I would like to thank my fiancé for their patience and unwavering emotional support during a challenging time.</p> <p>Thank you all for your patience and support.</p> <p>&ndash; Drew DeVault</p> Information regarding the SourceHut outage https://sourcehut.org/blog/2024-01-16-sourcehut-outage/ Tue, 16 Jan 2024 00:00:00 +0000 https://sourcehut.org/blog/2024-01-16-sourcehut-outage/ <p>SourceHut is currently experiencing an extended outage due to a distributed denial-of-service (DDoS) attack. We have been hard at work restoring service to our users, and expect the remaining services to come online this week. Thank you for your patience and words of support, we appreciate it very much.</p> <p>Once we have finished handling the majority of the work associated with the outage mitigations, we will be publishing a full post-mortem. For up-to-date information regarding the status of the outage and work associated with it, please consult <a href="https://status.sr.ht">status.sr.ht</a>.</p> <p>The billing system has been disabled for the duration of the outage: you will not be charged until we have fully restored service. Once restored, we will credit paid users with service for the duration of the outage.</p> <p>The current service status is as follows:</p> <table> <thead> <tr> <th>Service</th> <th style="min-width: 300px">Status</th> </tr> </thead> <tbody> <tr> <td>sr.ht (project hub)</td> <td class="text-success">Full service</td> </tr> <tr> <td>meta.sr.ht</td> <td class="text-success">Full service</td> </tr> <tr> <td>git.sr.ht</td> <td><span class="text-success">Full service</span><sup>1</sup></td> </tr> <tr> <td>hg.sr.ht</td> <td><span class="text-success">Full service</span><sup>1</sup></td> </tr> <tr> <td>lists.sr.ht</td> <td class="text-success">Full service</td> </tr> <tr> <td>todo.sr.ht</td> <td class="text-success">Full service</td> </tr> <tr> <td>man.sr.ht</td> <td class="text-success">Full service</td> </tr> <tr> <td>paste.sr.ht</td> <td class="text-success">Full service</td> </tr> <tr> <td>builds.sr.ht</td> <td><span class="text-success">Full service</span></td> </tr> <tr> <td>chat.sr.ht</td> <td class="text-success">Full service</td> </tr> <tr> <td>pages.sr.ht</td> <td><span class="text-warning">Degraded performance</span><sup>2</sup></td> </tr> </tbody> </table> <p><sup>1</sup> We have restored git and hg from backups which were several hours old at the time the outage began, and manually imported changes which took place between the time of the last backup and the start of the outage.</p> <p>If your repository is still out-of-date, please take the following steps:</p> <ol> <li>If you have access to the up-to-date repository locally, please <code>git push</code> or <code>hg push</code> your changes to bring the online version up-to-date.</li> <li>If you do not have access to your repository locally, please <a href="mailto:~sircmpwn/[email protected]">contact support</a> for assistance.</li> </ol> <p><sup>2</sup> pages.sr.ht is online for full service, with the following caveats:</p> <ol> <li>Publish operations are working with degraded performance</li> <li>Manual intervention is required for users using custom domains with apex records (e.g. example.org rather than subdomain.example.org)</li> </ol> <p>For users with apex records, please update your apex record as follows:</p> <pre><code>@ IN A 46.23.81.157 </code></pre> <p>This IP address is available on a temporary basis. Make sure your email address on file is up-to-date; we will email you if and when it changes to notify you of the steps required to update your website.</p> SourceHut's 2022 Financial report https://sourcehut.org/blog/2023-03-27-2022-financial-report/ Mon, 27 Mar 2023 00:00:00 +0000 https://sourcehut.org/blog/2023-03-27-2022-financial-report/ <p>In summary, SourceHut continues to be sustainable, profitable, and growing. We continued to grow YoY between 2021 and 2022. We were able to make some significant investments, particularly in establishing a new datacenter presence in Europe, and we intend to expand this investment over the course of 2023 and 2024, and we have plenty of capital to invest in this and other business initiatives.</p> <p><small>Disclaimer: this report is a summarized approximation of our financials, and is not used for tax purposes.</small></p> <h2 id="2022-revenue-sources">2022 revenue sources</h2> <p>SourceHut has two main revenue streams:</p> <ol> <li>Paid subscriptions for the forge platform, which are generally consistent</li> <li>Contracts via our <a href="https://sourcehut.org/consultancy/">consulting arm</a>, which are generally more inconsistent</li> </ol> <p>We use the forge platform revenue as the basis for our financial planning and sustainability model, and treat consulting revenue as capital to fund new projects and investments.</p> <h3 id="platform-revenue">Platform revenue</h3> <p>We issued 12,965 invoices in 2022. Subscriptions are available at three price points: $2, $5, and $10; billed monthly, or annually for a 2 month discount. Invoices paid in 2022 break down as follows:</p> <pre tabindex="0"><code>6,530 $ 2 (paid monthly) 2,456 $ 5 (paid monthly) 917 $10 (paid monthly) 2,141 $ 2 (paid yearly) 604 $ 5 (paid yearly) 227 $10 (paid yearly) </code></pre><p>The total revenue from platform subscriptions in 2022 was $132,226.50, which, after payment processing fees, becomes $123,677.57; a 25% increase over 2021. In 2022 a total of 8,544 users signed up for an account, of which 1,066 have paid for their account. This is a conversion rate of about 12%, which is comparable to 2021. Among all registered users (35,877 at the time of writing), about 11% have paid accounts (5,651).</p> <p>When the beta is completed, all users who own resources on SourceHut (source code repositories, mailing lists, bug trackers, etc) will be expected to pay for their account. Users who contribute to projects owned by others are not expected to pay, and users who wish to own resources but cannot afford the subscription fee will be offered financial aid. In 2022, 81 users received financial aid; 100% of requests for financial aid in 2022 were approved.</p> <p>The main reasons cited in applications for financial aid remain largely the same as 2021:</p> <ul> <li>Inability to pay due to financial constraints</li> <li>Lack of support for their preferred payment method</li> <li>Political sanctions due to the situation in Ukraine and Russia</li> </ul> <h3 id="consulting-revenue">Consulting revenue</h3> <p>SourceHut accepts consulting projects at the discretion of our full-time engineers, part-time. These contracts are executed in public and are required to only produce free and open source software.</p> <p>In total, SourceHut received $367,810 in revenue from consulting engagements in 2022.</p> <h3 id="summary-of-revenue">Summary of revenue</h3> <p>Our total revenue from all sources for 2022, before taxes, expenses, and fees, was $505,307.</p> <h3 id="cash-on-hand">Cash on hand</h3> <p>At the close of the year, we had $124,964 USD and €23,297 EUR in cash on hand.</p> <h2 id="2022-expenses">2022 expenses</h2> <p>In 2022 we had the following costs, excluding payroll:</p> <pre tabindex="0"><code>$20,103 European infrastructure investment $12,018 Infrastructure (colocation, power, network, etc) $ 8,548 Payment processing fees $ 1,861 Sponsorships (OpenStreetMap, Codeberg) $ 1,353 Business-related travel (events) $ 1,309 Services (Migadu, third-party backups) $ 1,153 Misc. equipment $ 816 Domain name registrations $ 209 Misc. other </code></pre><p>Each of our three staff earns a fixed $2500 monthly base pay, and received a $5000 bonus. Staff and contractors (a total of five people in 2022) receive additional income from the consulting arm which varies depending on the contract and amount of time worked.</p> <p>Base pay for 2022 works out to about $105,000. Including compensation for consulting-related work, the total spent on payroll in 2022 is about $250,000.</p> <p>Figures for staff compensation are sensitive to currency-related factors due to our presence in the US, Canada, and Europe; these figures are more approximate than the rest of the report.</p> <p>Our total expenses and investments for 2022 were approximately $272,000.</p> <h2 id="2022-financial-summary">2022 financial summary</h2> <dl> <dt>Revenue</dt> <dd>$505,307</dd> <dt>Expenses &amp; investments</dt> <dd>-$272,688</dd> <dt>Taxes</dt> <dd>-$60,000 (approx)</dd> <dt>Profit</dt> <dd>$172,619 (approx)</dd> </dl> <p>Fun fact: as of this year, the lifetime revenue for SourceHut has exceeded $1M USD.</p> <h2 id="expectations-for-2023">Expectations for 2023</h2> <p>We have three full-time staff paid under the standard compensation model, and about $1400/mo in recurring expenses. Currently, we make about $11000/mo from the platform, putting our monthly profit at about $2000, without factoring in consulting revenue. Thus, the platform provides for a sustainable business independently of our other lines of business.</p> <p>The breakdown of active subscriptions at the time of writing is as follows:</p> <pre tabindex="0"><code>$2 monthly 595 users $5 monthly 231 users $10 monthly 79 users $2 yearly 2,137 users $5 yearly 609 users $10 yearly 234 users </code></pre><p>We anticipate spending more on our European datacenter investment as we continue building it out, and we hope to shut down the Philadelphia datacenter in 2023 or early 2024, saving about $600/mo in operating expenses.</p> <p>We have closed out a major consulting engagement in Q1 2023 and we anticipate a significant reduction in consulting revenue as a consequence. We hope to complete the beta this year (you may have heard that before&hellip;), which would likely correspond with a significant increase in platform revenue.</p> <p>We also anticipate moving some or all our platform revenue into Europe in 2023. We hope to be dealing primarily in Euro by 2024.</p> <h2 id="conclusion">Conclusion</h2> <p>In short, SourceHut is profitable and is comfortably succeeding in its efforts to provide sustainable software development &amp; infrastructure for the free and open source software community. We remain committed to investing 100% of our profit into the free and open source community. I want to extend my thanks to the SourceHut community for its role in achieving our goals: sincerely, thank you.</p> SourceHut will (not) blacklist the Go module mirror https://sourcehut.org/blog/2023-01-09-gomodulemirror/ Mon, 09 Jan 2023 00:00:00 +0000 https://sourcehut.org/blog/2023-01-09-gomodulemirror/ <p><strong>Update 2023-01-31</strong>: Russ Cox of the Go team reached out to us to address this problem. After some discussion, an acceptable plan was worked out. The Go team is working on deploying an update to the &ldquo;go&rdquo; tool to add a -reuse flag, which should substantially reduce the traffic generated by this system for all users of Go.</p> <p>In the meantime, the automated refresh traffic from proxy.golang.org was disabled for SourceHut, which the Go team assures us should have little-to-no impact on users and which reduces the burden on our system to a managable level. Following this change by the Go team, we have observed traffic from the Go module mirror reduced to an acceptable level. The Go team has decided that the automatic refresh behavior is their responsibility, not the responsibility of other operators, so any other small hosts will hopefully not be affected as the Go team will enable or disable the refresh behavior at their discretion with the burden on third-party operators in mind.</p> <p>Consequently, we have cancelled our plans to disable Go traffic to git.sr.ht. No action is required by users to continue receiving service. Thanks Russ!</p> <p>The original post can be read below.</p> <hr> <p>SourceHut will disable git access for the <a href="https://proxy.golang.org/">Go Module Mirror</a> on February 24th, 2023. This will cause a service impact for Go users. This article explains why this step is necessary and how Go users can work around the issue.</p> <h2 id="tldr">tl;dr</h2> <p>From February 24th, users running <code>go get</code> or a similar command on Go packages which import modules from SourceHut repositories will be met with an error message similar to the following:</p> <pre tabindex="0"><code>$ go get go: downloading git.sr.ht/~sircmpwn/foobaz v0.0.0-20230108094957-81402546c10e go: git.sr.ht/~sircmpwn/[email protected]: verifying module: git.sr.ht/~sircmpwn/[email protected]: reading https://sum.golang.org/lookup/git.sr.ht/~sircmpwn/[email protected]: 404 Not Found server response: not found: git.sr.ht/~sircmpwn/[email protected]: invalid version: git ls-remote -q origin in /tmp/gopath/pkg/mod/cache/vcs/568e5edafe93f7887c0b6f718b0f17ea91c63c35822fb28628535f172b5429b7: exit status 128: fatal: unable to access &#39;https://git.sr.ht/~sircmpwn/foobaz/&#39;: The requested URL returned error: 429 </code></pre><p>The following workaround will correct the issue:</p> <pre tabindex="0"><code>$ export GOPRIVATE=git.sr.ht $ go get # works </code></pre><p>For more detail, read on.</p> <h2 id="background">Background</h2> <p>The Go programming language fetches modules via git, such that a user who imports &ldquo;<a href="https://git.sr.ht/~sircmpwn/dowork">git.sr.ht/~sircmpwn/dowork</a>&rdquo; will cause the toolchain to fetch the corresponding repository via git in order to make it available in the user&rsquo;s Go environment. Each of these requests is routed through a proxy service at <a href="https://proxy.golang.org/">proxy.golang.org</a>, which provides a number of features:</p> <ul> <li>Offers reliable and fast access to module downloads via Google&rsquo;s cache</li> <li>Stores redundant copies of Go modules to ensure availability</li> <li>Records an independent source of their checksum for the checksum database</li> <li>Provides an index of new Go modules</li> </ul> <p>This comes with a number of downsides. For example, most Go users are unaware that every package they fetch is accompanied by a request to Google&rsquo;s servers, and implies a trust relationship with Google to return authentic packages. Additionally, should the underlying source repository disappear or become out of sync with the cache, the problem is hidden from Go users, which can cause their software to become dependent on modules or module versions which no longer exist.</p> <p>More importantly for SourceHut, the proxy will regularly fetch Go packages from their source repository to check for updates &ndash; independent of any user requests, such as running <code>go get</code>. These requests take the form of a complete git clone of the source repository, which is the most expensive kind of request for git.sr.ht to service. Additionally, these requests originate from many servers which do not coordinate with each other to reduce their workload. The frequency of these requests can be as high as ~2,500 per hour, often batched with up to a dozen clones at once, and are generally highly redundant: a single git repository can be fetched over 100 times per hour.</p> <p>This traffic produces an excessive background workload which is constantly being serviced by git.sr.ht. Due to the relatively large traffic requirements of git clones, this represents about 70% of all outgoing network traffic from git.sr.ht. A single module can produce as much as 4 GiB of daily traffic from Google.</p> <h2 id="seeking-other-solutions">Seeking other solutions</h2> <p>Blacklisting GoModuleMirror is our last resort, and we wanted to avoid it if possible. We attempted to work with the Go team on a solution, but were unsuccessful.</p> <p>On February 24th, 2021, we <a href="https://github.com/golang/go/issues/44577">reported an issue</a> to the Go team regarding this problem. The Go team initially helped us narrow down the cause, first by setting an appropriate User-Agent to help identify this traffic, then through discussions regarding the behavior of this system. We made recommendations to Google for how to service their requirements without generating an excessive amount of redundant traffic. However, the discussion stalled and no further changes were made by Google to address the issue, and we continued to receive an excessive amount of traffic from the module mirror.</p> <p>The situation remained so for over a year. In that time, I was banned from the Go issue tracker without explanation, and was unable to continue discussing the problem with Google. With few options left, I wrote <a href="https://drewdevault.com/2022/05/25/Google-has-been-DDoSing-sourcehut.html">a blog post</a> on May 25th, 2022 outlining the issue and petitioning the public for support in addressing this problem. However, the problem remains unsolved.</p> <p>February 24th, 2023, the date that we plan to disable Go traffic, marks two years since the initial complaint was submitted to the Go team. The cost of bearing this traffic is no longer acceptable to us, and the Go team has made no attempts to correct the issue during this time. We want to avoid causing inconvenience for Go users, but the load and cost is too high for us to continue justifying support for this feature.</p> <h2 id="recommendations-for-the-go-team">Recommendations for the Go team</h2> <p>From February 24th, git clone requests with a GoModuleMirror User-Agent will receive a 429 (Too Many Requests) response. To restore service, we have the following recommendations for the Go team:</p> <ol> <li>Obey robots.txt, including the Crawl-Delay directive, to control the rate at which modules are fetched.</li> <li>Perform a shallow git clone rather than a full git clone; or, ideally, store the last seen commit hash for each reference and only fetch if it has been updated.</li> <li>Reduce redundant traffic: fetch each git repository less often. It should not be necessary to fetch the same git module up to 2,000 times per day.</li> </ol> <p>If these issues are addressed, we would be pleased to re-enable GoModuleMirror&rsquo;s access to our services. The Go team can reach me <a href="mailto:[email protected]">via email</a> to discuss the matter further, if you have ideas for other solutions or require any additional details to address the problem.</p> <h2 id="recommendations-for-go-users">Recommendations for Go users</h2> <p>Unfortunately, this will affect Go users and will require workarounds to be implemented in order to compile Go software which depend on modules hosted on git.sr.ht. If you encounter an error similar to the following:</p> <pre tabindex="0"><code>$ go get go: downloading git.sr.ht/~sircmpwn/foobaz v0.0.0-20230108094957-81402546c10e go: git.sr.ht/~sircmpwn/[email protected]: verifying module: git.sr.ht/~sircmpwn/[email protected]: reading https://sum.golang.org/lookup/git.sr.ht/~sircmpwn/[email protected]: 404 Not Found server response: not found: git.sr.ht/~sircmpwn/[email protected]: invalid version: git ls-remote -q origin in /tmp/gopath/pkg/mod/cache/vcs/568e5edafe93f7887c0b6f718b0f17ea91c63c35822fb28628535f172b5429b7: exit status 128: fatal: unable to access &#39;https://git.sr.ht/~sircmpwn/foobaz/&#39;: The requested URL returned error: 429 </code></pre><p>You can correct it by bypassing proxy.golang.org:</p> <pre tabindex="0"><code>$ export GOPRIVATE=git.sr.ht $ go get # works </code></pre><p>We will enable these variables by default for builds.sr.ht jobs prior to disabling service for the Go module mirror.</p> <p>We understand if Go users need to migrate away from SourceHut to deal with these problems. We apologise for this inconvenience, and we hope to see you return should the problem be resolved. The SourceHut team is available to assist with any necessary migration efforts via <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a>.</p> NLnet funding comes to an end https://sourcehut.org/blog/2022-11-21-nlnet-grant-conclusion/ Mon, 21 Nov 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-11-21-nlnet-grant-conclusion/ <p>Sourcehut was <a href="https://sourcehut.org/blog/2022-01-10-nlnet-graphql-funding/">selected for an NLnet grant</a> in January of this year. <a href="https://nlnet.nl">NLnet Foundation</a> is a Dutch organization which funds many projects to promote an open and secure internet.</p> <p>The typical NLnet grant is structured by milestones. At the beginning of the grant, a project plan is drafted containing the milestones to be completed and an agreed upon payment for each milestone. Once a milestone is completed, NLnet verifies that the milestone had been completed and approves the payment. If you think this might be a good fit for your project, consider <a href="https://nlnet.nl/propose/">applying for a grant</a>!</p> <p>Our grant work focused on completing the GraphQL APIs for Sourcehut services to help with Sourcehut&rsquo;s API 2.0 efforts. This work included many changes and improvements to the GraphQL APIs as well as implementing support for <a href="https://sourcehut.org/blog/2021-08-25-graphql-native-webhooks/">GraphQL-native webhooks</a>.</p> <p>Implementing GraphQL-native webhooks for git.sr.ht was the first milestone on our roadmap. This work involved:</p> <ol> <li>Designing and implementing the API for creating GraphQL webhooks</li> <li>Updating the GraphQL mutations to trigger webhooks</li> <li>Updating the Python frontends to route all necessary operations through the GraphQL APIs so that webhooks are triggered</li> <li>Updates to ancillary services/daemons (gitsrht-shell and gitsrht-update-hook)</li> </ol> <p>A similar process was followed for hg.sr.ht, todo.sr.ht, builds.sr.ht, lists.sr.ht, paste.sr.ht, and pages.sr.ht.</p> <p>Our focus then turned towards implementing a GraphQL API for hub.sr.ht. Near the end of June I began experimenting with GraphQL Federation in the hopes that it would make implementing the hub.sr.ht GraphQL API easier. This work led to the development of <a href="https://git.sr.ht/~sircmpwn/api.sr.ht">api.sr.ht</a>, a GraphQL API gateway.</p> <p>Before we can adopt GraphQL Federation, we needed to unify user IDs. Previously, user IDs were not guaranteed to be the same across SourceHut services. This did not play well with GraphQL Federation, which requires some sort of unique key to identify users across services. Patches for nearly every Sourcehut service were needed to address the issue.</p> <p>In order to ensure that the ID unification roll-out went as smoothly as possible, we decided that we needed better tools for testing. This resulted in the development of <a href="https://git.sr.ht/~sircmpwn/srht-fakedb">srht-fakedb</a>, a tool to populate Sourcehut service databases with fake data for testing purposes. The ID unification roll-out took place on October 26. With that now out of the way, work on the hub.sr.ht GraphQL API can resume.</p> <p>October 30 officially marks the end of the NLnet grant. We achieved most of what we set out to accomplish, and some more. We&rsquo;ll be wrapping up this work on SourceHut&rsquo;s dime in the coming weeks.</p> <p>Working with NLnet has been a great experience. Many thanks to <a href="https://nlnet.nl">NLnet</a> and <a href="https://nlnet.nl/NGI0/">NGI Zero</a> for sponsoring this work! We appreciate your generosity, and are looking forward to more projects developing under your fundraising umbrella.</p> Four years of SourceHut https://sourcehut.org/blog/2022-11-15-four-years/ Tue, 15 Nov 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-11-15-four-years/ <p>Today is the fourth anniversary of <a href="https://drewdevault.com/2018/11/15/sr.ht-general-availability.html">SourceHut&rsquo;s public opening</a>. In these four years, we have developed a free software platform which hosts nearly 10,000 projects, among them more than 68,000 repositories, 5,000 mailing lists with nearly a quarter-million emails, 6,500 bug trackers hosting 50,000 tickets, and 914 build-days over 880,000 jobs on builds.sr.ht, all in the service of our 33,516 users.</p> <p>I&rsquo;m tremendously proud of the community that has grown on this platform. I offer my sincere thanks to the thousands of people who have joined SourceHut and helped build a welcoming, productive community of free software developers. I offer my thanks to you, dear reader, for your profound role in these achievements. I struggle to find the right words to express the enormity of my gratitude.</p> <p>In lieu of adequate words to describe it, we strive to express this gratitude through our actions. Our work is entirely free software, and our community are co-owners in it; our hundreds of contributors have retained the copyright for their work and our copyleft licenses enforce our promise to forever remain free software. Many of these contributors have graciously stepped into roles as maintainers of various subsystems in their lines of expertise, and we have offered them trust and responsibility equal to the degree of their contributions and investment.</p> <p>We have further increased our commitment to transparency and honesty in our affairs this year, be it with our <a href="https://sourcehut.org/blog/2022-04-08-2021-financial-report/">financial reporting</a>; operations <a href="https://man.sr.ht/ops/">wiki</a>, <a href="https://metrics.sr.ht">data</a>, and <a href="https://lists.sr.ht/~sircmpwn/sr.ht-ops">monitoring</a>; our <a href="https://man.sr.ht/staff/">staff wiki</a>; or cultural artifacts such as striving to make our staff members directly accessible to users for addressing their needs. We have consulted you every step of the way, sought out and honored your insights, and carefully crafted our incentives to institutionalize a system that places your interests at the forefront.</p> <p>I&rsquo;m honored to be of service to the free software community, and I hope that we will continue to improve and grow to thrive in this role, and do our part to ensure the success of the free software movement.</p> <p>With all of this in mind: what happened this year, and what can we look forward to for next year?</p> <h2 id="the-year-in-review">The year in review</h2> <p>SourceHut development in the past year has been focused on completing the roll-out of our GraphQL APIs (aka API 2.0). One of the major concerns for the alpha is the completion of a robust and stable API that we&rsquo;re comfortable supporting for a long time. This effort has been quite successful; all of the major services now support GraphQL and we&rsquo;re preparing to build out the stragglers (project hub and man.sr.ht) over the next few weeks. With the planned development of GraphQL federation, we will complete a system which allows the federated mini-services of SourceHut to interoperate with one another in a much more flexible and powerful manner, while still retaining their independence and flexibility for third-party installs that only need a subset of the services.</p> <p>This period has not been absent of new features, however. We also completed and released <a href="https://sourcehut.org/blog/2021-11-29-announcing-the-chat.sr.ht-public-beta/">chat.sr.ht</a>, a hosted IRC bouncer service for SourceHut users. This software is built on <a href="https://sr.ht/~emersion/soju">soju</a> and <a href="https://sr.ht/~emersion/gamja">gamja</a>, respectively a bouncer and webchat service, developed as free software by SourceHut&rsquo;s own Simon Ser. This service makes IRC much more accessible and easy to use, and makes it easy for projects on SourceHut, and their contributors, to maintain and access real-time chat services for development discussions and end-user support — and for fun, plenty of us use IRC to hang out with our friends! Simon also began work on <a href="https://sr.ht/~emersion/hut/">hut</a> this year, which is a command line tool for interfacing with SourceHut that has become a staple of many of our users&rsquo; workflows.</p> <p>We also expanded our roster this year. We brought on Conrad Hoffman as SourceHut&rsquo;s newest full-time developer, who has been putting his talents to good use to help prepare us to move our infrastructure into the EU. We also received a generous grant from <a href="https://sourcehut.org/blog/2022-01-10-nlnet-graphql-funding/">NLnet</a>, which covered the costs to bring Adnan Maolood onto the project, whose efforts have been indispensable in helping to complete our GraphQL implementation.</p> <p>Many of our services have been expanded with additional features, including new features for SourceHut pages, a greater variety of build images for builds.sr.ht, finer access controls for all services, and, recently, the long-promised self-service account deletion and data export features — important for our goals of enabling user ownership over their own data.</p> <h2 id="coming-soon">Coming soon</h2> <p>As I mentioned earlier, we&rsquo;re putting a bow on GraphQL over the next several weeks, as we roll out the last couple of services and start setting up GraphQL federation. Federation will make it easier for us to implement greater inter-service connectivity, which will offer many useful improvements, including finally resolving the annoying &ldquo;how do I get to a project from its git repo&rdquo; problem once and for all.</p> <p>We also intend to overhaul our billing system in the foreseeable future, adding support for additional currencies and payment methods, such as payments in Euro via systems like SEPA or iDEAL. This will also resolve many long-standing papercuts with the billing system and provide users with a greater degree of control over their billing details. This is also important for the business side of SourceHut, since we&rsquo;ll be using this opportunity to migrate our platform revenue into Europe.</p> <p>On the subject of moving into Europe, we&rsquo;ve also started setting up our new European datacenter installation in Amsterdam. We have provisioned a few hosts and we&rsquo;re using them to experiment with better ways to deploy SourceHut infrastructure, including, yes, the dreaded Kubernetes. If this works out, many users who wish to deploy SourceHut into a typical cloud environment will find the task more easily done. We&rsquo;re also hoping to use this effort to make strides towards turning our four nines into five nines, improving on our already industry-leading stability.</p> <p>We also plan on tackling another long-awaited feature soon: user groups, or organizations. This and the other features described have been blocked on the completion of our GraphQL work, and with this work out of the way, it&rsquo;s time to prepare for a flurry of new feature development to round out the alpha and finally bring the SourceHut beta into life. All of these plans have one thing in common: they&rsquo;ve been identified since the start as our major priorities for the completion of the alpha. It&rsquo;s happening.</p> <h2 id="coming-later">Coming later</h2> <p>This covers what you can expect over the next several months, but I also want to spend a moment discussing some of the things we&rsquo;re planning to do in the longer term. Here are a few possible future services which are on our minds:</p> <h3 id="jobssrht">jobs.sr.ht</h3> <p>This service is something we drafted and mocked out several months ago, and it&rsquo;s been sitting on the backburner while we address more urgent priorities. The essential idea is to provide a jobs board for hiring developers to work on free software.</p> <p>Through a combination of hard work and luck, SourceHut has settled upon a financial model which allows us to sustainably work on free software projects in a manner compatible with our ethical obligations. We want to help others in the free software ecosystem achieve similar goals for themselves, so that the free software world can grow and flourish on the backs of healthy and happy developers. To this end, we conceived of jobs.sr.ht.</p> <p>The plan is to allow users to list themselves on the platform so that interested clients can seek out free software developers to hire for projects. We want to accommodate a variety of approaches: a maintainer might be hired by their users to implement a desirable feature over the occasional weekend, or a group of free software developers could form a collective to take on more serious contracts to develop free software for the industry. An artist could list their services to design the mascot for new free software projects, or a maintainer could hire a talented developer to help them ship a new release.</p> <p>Here&rsquo;s the ticket: SourceHut will not charge any fees to either party beyond that of your existing SourceHut subscription. Users who receive financial aid will also be entitled to utilize this service. We&rsquo;ll cover the expense of operating this platform out of our normal platform revenue. Additionally, we will make no efforts to insert ourselves between contractors and their clients. You will be responsible for writing and agreeing to your own contract terms, facilitating payment between yourselves, and will communicate normally through email, rather than from within a walled garden. We will <em>never</em> hold your means of income hostage. If you choose to leave or move elsewhere, you take all of your contracts with you, and can import your details into an instance of jobs.sr.ht hosted by anyone else.</p> <h3 id="namessrht">names.sr.ht</h3> <p>An older idea that we&rsquo;re still interested in working on is names.sr.ht, a domain registrar and DNS hosting service. This concept is born out of the frustrations of using a janky JavaScript record editor to update DNS records: what if we could just push a zone file to a git repository instead?</p> <p>We also intend to act as a domain registrar (or rather as a reseller, we don&rsquo;t have the resources to be a first-class registrar). We will not charge any additional margin over the price we receive, and instead will include these services as part of your normal SourceHut subscription fee. As our purchase volume grows, we will be able to negotiate bulk discounts and pass the reduced prices back to you.</p> <p>Not sure when we can expect to see this service — it&rsquo;ll probably be done when one of our staff members gets bored for a couple of weeks and blitzes out the initial prototype. In any case, I&rsquo;m looking forward to it.</p> <h3 id="mailsrht">mail.sr.ht?</h3> <p>We&rsquo;re thinking about developing a hosted email service. Email is, as you know, very important to SourceHut&rsquo;s workflow. We would love to provide a killer hosted email experience for users to better facilitate this.</p> <p>Such a service would include all of the trimmings that we feel are essential — standard protocols such as IMAP and SMTP, configurable sieve filters, unlimited domains, and so on. We may consider researching a model which allows for bulk mail delivery, naturally subject to the condition that you are not using it for spam — hosting something like a development mailing list or sending our confirmation emails for sign-ups to your Mastodon instance would be more appropriate. We&rsquo;ll also add some features which are unique to SourceHut, such as close integration with services like lists.sr.ht — and wouldn&rsquo;t it be nice to see the CI status of a patch and click &ldquo;apply&rdquo; right in your inbox? Once names.sr.ht is rolled out as well, we can use it to make it easy to manage the pesky DNS settings necessary to ensure smooth delivery and compatibility with things like mailing list forwarding.</p> <h2 id="in-conclusion">In conclusion</h2> <p>It&rsquo;s been a great four years so far, and we have more great years to look forward to. We&rsquo;re well on our way to a more complete and reliable system, and we&rsquo;ve been able to provide more support for the free software ecosystem than I ever imagined possible. I&rsquo;ll re-iterate my thanks to you, dear reader, for reading this post, and for using SourceHut. You&rsquo;re the best.</p> <p>That&rsquo;s all for today. Take care!</p> SourceHut terms of service updates, cryptocurrency-related projects to be removed https://sourcehut.org/blog/2022-10-31-tos-update-cryptocurrency/ Mon, 31 Oct 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-10-31-tos-update-cryptocurrency/ <p>SourceHut is planning to roll out updates to our terms of service, effective in 2023. The changes most likely to impact users is the prohibition of cryptocurrency- or blockchain-related projects on SourceHut.</p> <p>These domains are strongly associated with fraudulent activities and high-risk investments which take advantage of people who are suffering from economic hardship and growing global wealth inequality. Few to no legitimate use-cases for this technology have been found; instead it is mostly used for fraudulent &ldquo;get rich quick&rdquo; schemes and to facilitate criminal activity, such as ransomware, illicit trade, and sanctions evasion. These projects often encourage large-scale energy waste and electronics waste, which contributes to the declining health of Earth&rsquo;s environment. The presence of these projects on SourceHut exposes new victims to these scams and is harmful to the reputation of SourceHut and its community.</p> <p>We recognize that the basic idea of a blockchain, as it were, may be generally useful. However, most projects which market themselves with blockchain technology are subject to the same social ills as cryptocurrency. Consequently, we have chosen to include &ldquo;blockchain&rdquo; related projects in this ban for the time being.</p> <p>We will exercise discretion when applying this rule. If you believe that your use-case for cryptocurrency or blockchain is not plagued by these social problems, you may ask for permission to host it on SourceHut, or appeal its removal, by <a href="mailto:[email protected]">contacting support</a>.</p> <p>Projects which seek out cryptocurrency donations are strongly discouraged from doing so, but will not be affected by this change.</p> <h2 id="what-to-do-if-you-dont-agree-to-the-changes">What to do if you don&rsquo;t agree to the changes</h2> <p>If your project is affected by these changes, or you do not agree with them, you have until January 1st, 2023 to migrate to another platform. You may use <a href="https://sr.ht/~emersion/hut/">hut(1)</a> to obtain an export of your account data using standard formats that you may import into a third-party SourceHut instance, or another host which is compatible with these formats (such as Codeberg, GNU Mailman, etc). If you wish, you may request to have your account deleted by <a href="mailto:[email protected]">contacting support</a>.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p> <h2 id="other-changes-to-the-terms-of-service">Other changes to the terms of service</h2> <p>Changes to the terms of service require notifying all users, so we try to batch them when possible to reduce the number of annoying emails everyone has to deal with. You can review a complete diff of the changes <a href="https://paste.sr.ht/~sircmpwn/b966c63c14df7d233647ef605961c7654430557c">here</a>.</p> <p>Here are some other changes we&rsquo;re including in this update:</p> <h3 id="applicability-of-dutch-law">Applicability of Dutch law</h3> <p>We are in the process of moving SourceHut to the European Union, and have incorporated in the Netherlands. Consequently, the terms have been updated to clarify that users are required to comply with Dutch law in addition to US law. The requirement to comply with US law will be removed in a future update after we close the US entity.</p> <h3 id="threatening-and-harassing-others">&ldquo;Threatening and harassing others&rdquo;</h3> <p>We have expanded the list of prohibited behaviors to include &ldquo;threatening and harassing others&rdquo;. We have already banned users for this behavior (we can terminate service at our discretion), but we decided to make this explicit. The scope of this is intended to cover incidents where users harass other users or make bigoted, racist, homophobic, transphobic, etc, comments on our platform.</p> <p>We take account termination seriously, and use it only as a last resort. In the history of SourceHut, only two users have been banned.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> The first user was harassing maintainers and failed to respond to emails seeking to discuss their behavior. The second used SourceHut to advocate for the rights of pedophiles to sexually abuse children.</p> <h3 id="revised-content-license">Revised content license</h3> <p>We have updated the license which is granted to SourceHut when you upload content to our services. The purpose of this license is to ensure that we have sufficient rights over your content to do our job, and grants us permission to do things like display your content on the website.</p> <p>We have clarified how this works in situations where you do not own the copyright over the content you upload, such as when you mirror a free software project on SourceHut, or when a project&rsquo;s copyright is collectively held by many contributors. We have also removed the &ldquo;indefinite&rdquo; license and updated the terms so that the content license is terminated automatically when you remove your content from the services.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>We would like to have self-service account deletion implemented by the time these changes are implemented, but it&rsquo;s a complex feature that may require more time to implement. In the meantime, manual requests for account deletion will be processed normally.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>Among accounts representing real people, not including bulk spam registrations, cryptocurrency mining abuse, etc.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on SourceHut? October 2022 https://sourcehut.org/blog/2022-10-18-whats-cooking-october-2022/ Tue, 18 Oct 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-10-18-whats-cooking-october-2022/ <p>Greetings! Today we&rsquo;re joined by 623 fresh new users, bringing our total of 32,904. News is light for this month, since I&rsquo;ve been taking some time off. However, things are still gradually rolling forwards, and we have some important internal changes landing soon. I&rsquo;ll give you the details.</p> <h2 id="planned-maintenance-next-week">Planned maintenance next week</h2> <p>We are rolling out a major, high-risk software upgrade on Monday, October 24th. This will require an outage, and we have set up a maintenance window starting from 09:00 UTC. For details, see <a href="https://status.sr.ht/issues/2022-10-24-planned-outage/">status.sr.ht</a>.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>Vlad-Stefan Harbuz&rsquo;s patches adding <a href="https://reuse.software/spec/">REUSE</a> support to git.sr.ht have landed this month. Software which is compatible with the REUSE specification will enjoy <a href="https://git.sr.ht/~vladh/fotografiska/licenses">native support</a> for license analysis in git.sr.ht. This feature will be expanded in the future. Thanks Vlad!</p> <h2 id="listssrht">lists.sr.ht</h2> <p>Thanks to Tanguy Fardet&rsquo;s efforts, mailing list owners are now allowed to configure their lists to allow multipart text/html messages. Such emails are still required to have a text/plain part. This is disabled by default for new mailing lists and is discouraged for most users — you&rsquo;ll know if you need it.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>Simon has continued working on improving our OAuth 2.0 implementation, aligning us closer with the specification and making it possible to use it with more out-of-the-box OAuth 2.0 client libraries. Please file tickets if you notice any additional discrepancies.</p> How to help improve SourceHut's design https://sourcehut.org/blog/2022-10-13-how-to-improve-sourcehut-design/ Thu, 13 Oct 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-10-13-how-to-improve-sourcehut-design/ <p><a href="https://sourcehut.org">SourceHut</a> is a software development forge and it is designed with the software engineer&rsquo;s needs first and foremost. The design prioritizes things like page speed, minimal distractions, and information-forward layouts. It does not prioritize aesthetics, and perhaps it shows.</p> <p>Like many free software projects, SourceHut encourages contributions from its community in the form of patches. Not all of these have to be changes to the software — we frequently receive patches improving the documentation, for example. There are many skillsets which are valuable to offer to a free software projects. One of these skills is design competence, and over the years a few people with this skillset have attempted to improve SourceHut&rsquo;s design, but many of their changes were rejected. Why? How can a designer succeed in improving SourceHut?</p> <p>SourceHut&rsquo;s design space imposes constraints on the visual design which present more of a challenge to the aspiring designer than most of the projects they may have worked on. We are open to (and excited about!) improvements to the SourceHut design, but such changes must be implemented within the constraints of our ethos, and these constraints are often unusual and unfamiliar to the typical web designer. SourceHut is an engineering tool first and foremost, and all of our design decisions are made with an eye on solving problems for software engineers. This is the prime directive, and all other concerns, such as subjective aesthetic value, are secondary to the prime directive.</p> <p>It is under this lens that any proposed design changes are evaluated, and for this reason many are rejected. A design change for SourceHut must be carefully thought out and must balance its aesthetic value with its effect on the utility, usability, and accessibility of the services. To offer a small example: several people have proposed making the <a href="https://git.sr.ht/~sircmpwn/helios/tree/master/item/objects/memory.ha">source view</a> centered to match the rest of the UI. However, this would introduce a horizontal scroll for files with long lines, making it more difficult to read them. The prime directive of this page is reading code, therefore this change was rejected.</p> <p>Of course, looking nice does, in its own way, contribute to many of the same underlying values like usability and accessibility. A page which is pleasant to look at is more usable. The user&rsquo;s enjoyment of the service is derived in no small part from its aesthetic value, and that&rsquo;s important to us as well.</p> <p>The challenge is thus to come up with designs which are aesthetically pleasing, but also meet our goals for broad accessibility and utilitarianism, while simultaneously communicating our values and priorities. Our values differ substantially from other platforms in this space. GitHub, GitLab, Gitea, they are all fundamentally speaking the same design language and expressing the same values. Because our values differ, our design should differ, and distinguish us from the pack in a manner which makes our principles visually evident.</p> <p>A designer who hopes to rise to this challenge should understand and internalize these values, which is particularly difficult given the extent to which we reject the values of the mainstream &ldquo;modern web&rdquo;. Should you want to meet this challenge, the community would be thrilled to work with you. I would strongly recommend joining our <a href="https://man.sr.ht/support.md#real-time-chat">IRC channels</a> and seeking feedback early and incrementally — most design proposals for SourceHut fail due to seeking feedback too late or proposing a huge redesign all at once. So long as we work together, we will find success. Good luck!</p> SourceHut does not ask for IP assignment from employees or contributors https://sourcehut.org/blog/2022-10-09-ip-assignment-or-lack-thereof/ Sun, 09 Oct 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-10-09-ip-assignment-or-lack-thereof/ <p>A &ldquo;standard&rdquo; clause you&rsquo;ll see in most employment contracts is an IP assignment clause. This clause assigns the intellectual property produced by an employee in the course of their work to the business that they work for. This generally extends both to copyrights and patents, and the more egregious of these clauses include work done outside of company time and without the use of the company&rsquo;s assets and equipment. Often this is accompanied with a burdensome process of identifying every copyright owned by the employee on a little sheet that accompanies the employment contract.</p> <p>Free software projects overseen by businesses also often want to control the copyright of external contributors. This is usually done by imposing a Contributor License Agreement, or CLA, on the contributor before accepting their change. These either assign the contributor&rsquo;s copyright outright, or does so in all but name by signing over all of the rights associated with their copyright.</p> <p>In the absence of such agreements, copyright for each contribution to a free software project remains held by the contributors themselves. Thus, ownership of that project&rsquo;s IP is collectively held by its contributors. Consequently, the &ldquo;owners&rdquo;<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> of the project cannot change the license to make it more restrictive, or more permissive, or non-free outright, without the written consent of each of the copyright holders.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> The project stewards are offered the same FOSS license terms for each contribution that they offer to everyone else for their own.</p> <p>SourceHut does not ask our staff to sign an IP assignment, and we do not ask our external contributors to sign a CLA. Consequently, SourceHut, the business entity, does not own its intellectual property. It is collectively owned by the individuals who have worked on it, both internal and external. When I say SourceHut belongs to its users, I&rsquo;m not using flowery doublespeak — I mean it literally.</p> <p>To re-enforce this, we rely on copyleft software licenses. Copyleft, to offer a simplified explanation, essentially requires that any changes to the project must also be released under the same software license. If we held the copyright for our software, we could disregard these terms, but because contributors license <em>their</em> copyright to <em>us</em> under the same copyleft licenses, we are obligated to use their contribution under the same terms and release <em>our</em> changes as free software as well. If we used a permissive license like MIT or BSD, we could fork the project and keep our changes closed-source, but using copyleft closes this path to us and serves as a strong promise to the community that SourceHut will always be free software.</p> <p>We do things a bit differently from the industry &ldquo;standards&rdquo;. We honor and respect each contributor&rsquo;s work, both internal and external, and their copyright forms an important piece of the safeguards we use to establish trust with our community. We honor and respect our staff members as well, and do not impose upon them IP assignments, non-disclosure agreements, or non-competes. This approach is a more just way of doing business, and is our strategy for building a long-lived and sustainable free software platform, hand-in-hand with the community, on equal terms as peers working towards a shared vision.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>I&rsquo;ve taken to generally referring to people and entities in this role as &ldquo;stewards&rdquo;, because, well, they literally do not own it.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>They can also rewrite the contributions from those who do not agree to change the license.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on Sourcehut? September 2022 https://sourcehut.org/blog/2022-09-15-whats-cooking-september-2022/ Thu, 15 Sep 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-09-15-whats-cooking-september-2022/ <p>Guten Morgen, SourceHut! Today, I count 681 new users, for a grand total of 32281 registered users. As always, a warm welcome to them and the reminder to everyone else to help them feel welcome while they get settled. Today, I am filling in for Drew on short notice, so please excuse the brevity.</p> <h2 id="chatsrht">chat.sr.ht</h2> <p>Simon has done some excellent work simplifying the authentication workflow of <a href="https://chat.sr.ht">chat.sr.ht</a> for users. The new approach is based on standard OAuth, which means other users of soju (the IRC bouncer running on chat.sr.ht) can benefit from this feature and use any available OAuth server for authentication. You can read Simon&rsquo;s <a href="https://emersion.fr/blog/2022/irc-and-oauth2/" title="IRC × OAuth 2.0 - emersion">blog post</a> for all the details.</p> <h2 id="graphql">GraphQL</h2> <p>The ID unification rollout is still taking its toll. We are currently building a test setup (or rather, a <a href="https://git.sr.ht/~sircmpwn/srht-fakedb">test setup generator</a>) that is reasonably close to production, yet does not include any user data. This will give us the needed confidence that we can roll out this major change without breaking anything.</p> <p>In the meantime, the GraphQL API is now deemed mature enough that the <a href="https://meta.sr.ht/oauth2">OAuth2 dashboard</a> has been made the default in meta.sr.ht.</p> <h2 id="infrastructure">Infrastructure</h2> <p>SourceHut goes to Europe! Next week, the SourceHut team will meet in person to inaugurate our new data-center. We&rsquo;ll be installing the first couple of servers, but it will be another while before we will serve production traffic from there. We will use this chance for some experimentation to decide on the infrastructure we want to run SourceHut on in the coming years.</p> <h2 id="buildssrht">builds.sr.ht</h2> <ul> <li>Rocky Linux 9 is available</li> <li>Ubuntu Impish has been removed following its upstream deprecation</li> <li>NixOS 21.11 has been removed following its upstream deprecation</li> </ul> How does SourceHut's free software consultancy work? https://sourcehut.org/blog/2022-08-23-how-does-our-consultancy-work/ Tue, 23 Aug 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-08-23-how-does-our-consultancy-work/ <p>SourceHut offers a <a href="https://sourcehut.org/consultancy/">consultancy</a> in which we offer our services as experts in free software to work exclusively on free software development. Through this work we have developed improvements to Wayland, graphics, virtual reality, email, and more, entirely through free software developed in public. Our work can take the form of developing new free software from scratch, contributing improvements to projects that our client depends on, offering what sage advice we can spare, or, often, all of the above.</p> <p>How does this actually work in practice? Following a discussion in our off-topic IRC channel today, I thought that it would be nice to write about the actual logistics of our operation so that others who want to sell free software consulting services are better equipped to do so, and so that future customers know better what to expect from us.</p> <p>The process begins with client on-boarding. We don&rsquo;t do much in the way of marketing — customers mostly come to us. When someone new comes to us with an idea, the first thing we do is seek a basic alignment on the project goals and needs, on our process, and regarding our unique free-software requirements. We evaluate proposals based on a few criteria:</p> <ul> <li>Does this project benefit the free software ecosystem?</li> <li>Does our team have the necessary experience?</li> <li>Are the right engineers available to work on it?</li> </ul> <p>Roughly half of our proposals clear this stage. In addition to a reasonably complete project proposal, we need to establish with the client an understanding of our requirements, namely:</p> <ul> <li>All work is published under a free software or open source license</li> <li>All work is conducted in public — no <abbr title="non-disclosure agreement">NDA</abbr>s</li> </ul> <p>Though we require the results to be released to the public as free software, we&rsquo;re open to assigning copyright to the client. Not all clients want this, though. If the customer has a clear idea of what&rsquo;s required, a few emails back and forth are suitable to establish a consensus. If a deeper analysis is needed, we might ask for a temporary contract to cover costs of initial research and planning.</p> <p>Following this, we&rsquo;ll draft a contract and seek consensus on the expected pricing and effort required. Our contracts are short and simple, generally covering matters like logistics for payment and the contract period, but also explicitly addressing our requirements regarding subjects like software licenses. Sometimes the client prefers to use their own contract templates, which we&rsquo;re open to, but generally this requires more negotiation to remove &ldquo;standard&rdquo; clauses for things like NDAs.</p> <p>We bill for each of the engineers we plan to bring on board separately. Our pricing is essentially a function of two competing factors: we target free software and small- to medium-sized businesses, which pushes our prices down, and we offer high-end services from an experienced team, which pushes up. Right now this balance settles on a $250/hour and $150/hour standard base rate for our senior and junior engineers respectively.</p> <p>The rates are generally only somewhat negotiable — but we may tweak our rates depending on things like our perception of the positive impact a contract might have for free software, or the means of the client. An early-stage open hardware vendor might get a reduced rate for our work developing graphics drivers for them, for example. We will generally expect a deposit from unfamiliar customers.</p> <p>Once everything is signed and it&rsquo;s off to the races, the execution of these contracts involves a non-traditional planning style. We push back against suggestions like waterfall or agile, and prefer instead to work like a free software project often does — with broad long-term goals, loosely defined, and narrower short-term goals, more concretely defined. We also set research and planning as an objective in its own right, as this allows us to illuminate unknowns and secure a better idea of the implementation process for each task. We prefer to express progress and planning in terms of the complexity of the work required rather than the expected time to complete it.</p> <p>Facilitating this mutual understanding of the work involves monthly &ldquo;status update&rdquo; emails sent alongside the invoices for each month&rsquo;s work. These updates cover the tasks recently completed and those planned for the near future, and explain how these tasks relate to the broader objectives.</p> <p>This is a good opportunity for us to seek consensus where required. Often the client will follow up with questions and clarifications, which a brief email exchange squares up. We&rsquo;ll also use this as an opportunity to seek clarifications on our end, or to communicate when a decision is required from the client. We occasionally will entertain such exchanges mid-cycle as well, but we plan to anticipate decision points well before they become blockers so that we can work autonomously mid-cycle. We seek to understand and internalize the client&rsquo;s vision so that we can make the right choices autonomously, reducing the opportunities for our team to be blocked and increasing the client&rsquo;s confidence in the project.</p> <p>Though this approach is extraordinarily effective, it relies on a great deal of mutual trust. We aim to secure this by maintaining a reputation for careful, skillful engineering, fierce honesty and transparency, and a history of shipping reliable production software. Insisting on working on free software in public puts weight to these words: our results are independently verifiable.</p> <hr> <p>The model works. Our clients have expressed unanimous satisfaction with our services, and we&rsquo;ve been able to do a lot of great work for the free software community. Our successes includes <a href="https://git.sr.ht/~bl4ckb0ne/wxrc">VR on Wayland</a> and many improvements (<a href="https://gitlab.freedesktop.org/monado/monado/-/merge_requests?scope=all&amp;state=merged&amp;author_username=bl4ckb0ne">1</a>, <a href="https://gitlab.freedesktop.org/monado/monado/-/merge_requests?scope=all&amp;state=merged&amp;author_username=ddevault">2</a>, <a href="https://gitlab.freedesktop.org/monado/monado/-/merge_requests?scope=all&amp;state=merged&amp;author_username=emersion">3</a>) to the Monado OpenXR runtime, the <a href="https://github.com/Plagman/gamescope/pulls?q=is%3Apr+author%3Aemersion+is%3Aclosed">Wayland software</a> powering the <a href="https://www.steamdeck.com/en/">Steam Deck</a>, and a new <a href="https://sr.ht/~migadu/alps/">webmail</a> and a <a href="https://sr.ht/~sircmpwn/tokidoki/">calendaring and contacts server</a>.</p> <p>If you&rsquo;d like to hire us to work on your project, take a look at our <a href="https://sourcehut.org/consultancy/">consulting page</a> for details. If you&rsquo;d like to emulate us, I hope that you found this resource helpful. Feel free to ask for advice in #sr.ht.watercooler on Libera Chat.</p> <p>We have been planning to develop a jobs board for SourceHut users which allows FOSS developers to list themselves for hire called hire.sr.ht. We intend to provide this service as part of your normal SourceHut subscription,<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> and will not take a margin on top of your contracts. You would handle your own contracts and billing, control the communication channels with your clients, have the freedom to take clients off of the platform, and enjoy full ownership over your consulting income.</p> <p>We have not been able to prioritize this work, but we have developed <a href="https://git.sr.ht/~sircmpwn/hire.sr.ht">enough of it</a> that we can work with potential contributors. If you&rsquo;re interested in helping us bring this service to life, familiarize yourself with the existing code and see what you can do. Check out the GraphQL backend first. Patches to <a href="mailto:~sircmpwn/[email protected]">~sircmpwn/[email protected]</a>. Cheers!</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>Including for users who receive financial aid&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on SourceHut? August 2022 https://sourcehut.org/blog/2022-08-16-whats-cooking-august-2022/ Tue, 16 Aug 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-08-16-whats-cooking-august-2022/ <p>Good morning! 785 new users are joining us on this cool August morning, for a total of 31,600 SourceHut users. Remember to be kind and patient with our new members as they learn how to use the software and work with the communities here. We only have a short update for this month, so let&rsquo;s get right into it.</p> <h2 id="graphql">GraphQL</h2> <p>Work on GraphQL has slowed this month as we get ready to tackle a major change: ID unification. Each of our services has a separate database with their own user tables synchronized with meta.sr.ht&rsquo;s authoritative data, each of which has its own set of user IDs. This has worked fine thus far, but for the coming work on GraphQL federation, we will need to unify them. This is a major effort which will require thorough testing and a careful roll-out, and progress on other goals will slow as it&rsquo;s being done. Stay tuned.</p> <h2 id="infrastructure">Infrastructure</h2> <p>We have selected a new datacenter location for our European infrastructure roll-out and are working with hardware suppliers to provision an initial set of research servers to install. It will still be several months before we&rsquo;re ready to completely move our servers into the EU, but things are moving along.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>A new ticket resolution, CLOSED, has been added and made the default selection. The project hub has also been updated to support using CLOSES in commit trailers when pushing to git repositories.</p> <h2 id="buildssrht">builds.sr.ht</h2> <ul> <li>OpenBSD 7.1 is now available</li> <li>OpenBSD 6.9 has been removed following its upstream deprecation</li> <li>NixOS 21.11 is deprecated and will be removed shortly</li> <li>Ubuntu Impish is deprecated and will be removed shortly</li> </ul> <p>We are also expecting Rocky Linux 9 to be available soon.</p> <h2 id="dispatchsrht">dispatch.sr.ht</h2> <p>Dispatch is being deprecated. <a href="https://sourcehut.org/blog/2022-08-01-dispatch-deprecation-plans/">See the announcement</a> for the details.</p> Planned deprecation of dispatch.sr.ht https://sourcehut.org/blog/2022-08-01-dispatch-deprecation-plans/ Mon, 01 Aug 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-08-01-dispatch-deprecation-plans/ <p><a href="https://man.sr.ht/dispatch.sr.ht/">dispatch.sr.ht</a> is a SourceHut service which provides integrations between SourceHut and third-party services like GitHub and GitLab, and it is scheduled to be deprecated and shut down. Here&rsquo;s the plan:</p> <p><strong>2022-08-01</strong>: Creation of new dispatch tasks is disabled.</p> <p><strong>2022-09-01</strong>: Dispatch users will be emailed with information about migration.</p> <p><strong>2022-10-01</strong>: Dispatch is shut off.</p> <p>This blog post will explain the motivations for these changes and offer solutions for users who wish to migrate.</p> <h2 id="why-is-dispatch-being-deprecated">Why is dispatch being deprecated?</h2> <p>There are a few reasons for deprecating dispatch.</p> <p>For a start, dispatch has not lived up to its initial expectations. Initially envisioned as a kind of IFTTT-for-development, the actual implementation falls far short of that goal and there is no clear path for improvement. There is also not a clear path for upgrading dispatch to support our plans for the GraphQL rollout.</p> <p>Additionally, dispatch provides integrations with non-free services, which is something that we have a stated policy against. Dispatch pre-dates this policy and was grandfathered in — it was originally written to allow me to rig up builds for <a href="https://github.com/swaywm/sway">sway</a>, which is hosted on GitHub.</p> <p>Users of dispatch also tend to use more resources than other kinds of users. The GitHub and GitLab workflow encourages frequent pushes to PR/MR branches, which causes many builds to be submitted. builds.sr.ht is the most expensive service SourceHut operates, so this can add up. Among the top ten users ordered by total build-hours consumed, one is a cryptocurrency miner we banned, one is an account operated by a Linux distro that builds all of their packages on SourceHut,<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> and the remainder are GitHub users. In total, GitHub users account for 51% of all build hours executed in the lifetime of builds.sr.ht.</p> <p>At some point we have to question if this is in our best interests. These projects generally <em>only</em> use SourceHut for builds, and have no intention of migrating anything else. I would not necessarily have a problem with it if GitHub and GitLab were free software, per SourceHut&rsquo;s mission to &ldquo;make free software better&rdquo;. But as it is, it feels like we&rsquo;re propping up non-free forges and giving users an excuse not to <a href="https://sfconservancy.org/GiveUpGitHub/">migrate elsewhere</a>.</p> <p>So, in summary: dispatch is difficult to maintain and has no clear path for addressing its implementation problems, is exceptionally expensive to operate, violates our policies for integration with non-free software, and serves a community which is largely external to SourceHut and dependent on non-free platforms.</p> <h2 id="options-for-migration">Options for migration</h2> <p>All of that said, we don&rsquo;t want to leave users who are depending on dispatch out in the cold. To this end, we have been working on providing alternative means of achieving similar functionality. Today, dispatch provides four configurable &ldquo;tasks&rdquo;:</p> <ul> <li>GitHub commits to builds.sr.ht jobs</li> <li>GitHub pull requests to builds.sr.ht jobs</li> <li>GitLab commits to builds.sr.ht jobs</li> <li>lists.sr.ht patches to GitLab merge requests</li> </ul> <p>Each of these use-cases is now available via a third-party tool. For GitHub integration, see <a href="https://sr.ht/~emersion/hottub/">hottub</a>. For GitLab builds, see <a href="https://sr.ht/~emersion/dalligi/">dalligi</a>. Support for forwarding patches to merge requests is being implemented via <a href="https://git.sr.ht/~sircmpwn/hashiru">hashiru</a>, but this is not complete — it will be before dispatch is shut off.</p> <p>Affected users who wish to receive a refund for the remainder of the SourceHut subscription may <a href="mailto:[email protected]">contact support</a> to receive one.</p> <p>I hope that these tools will be effective for your project, and if you have any questions about migration we would be happy to assist you on IRC or on the sr.ht-discuss mailing list. However, I have a humble request for those who choose to migrate to these tools: if you are using a non-free platform like GitHub or GitLab (.com/EE) for your project&rsquo;s primary hosting, please make a plan to migrate from builds.sr.ht. GitHub provides GitHub Actions and GitLab has its own CI system as well. If you&rsquo;re not comfortable moving to SourceHut or another free-software platform, that&rsquo;s your choice and we respect it — but it is a bit burdensome for us to accommodate you. Thank you for your understanding.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>A use-case we are proud to support.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on SourceHut? July 2022 https://sourcehut.org/blog/2022-07-18-whats-cooking-july-2022/ Mon, 18 Jul 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-07-18-whats-cooking-july-2022/ <p>Good morning, SourceHut! Today we have 30,815 users, 1,203 of which are joining us for the first time this month — a big increase! To all of our new users: welcome! To all of our more tenured users: be sure to offer our new friends a warm welcome and do your part to help them learn how to use SourceHut.</p> <h1 id="graphql">GraphQL</h1> <p>Check this out:</p> <dl> <dt>meta.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>git.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>hg.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>todo.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>builds.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>lists.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>hub.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>paste.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>pages.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> </dl> <p>Adnan has been hard at work on GraphQL this month, and we&rsquo;re almost done. The last remaining API to be implemented is hub.sr.ht, but before we implement it, we&rsquo;ll be experimenting with <a href="https://www.apollographql.com/docs/federation/">GraphQL federation</a>. This will allow us to access every GraphQL API through a single endpoint, seamlessly querying resources like git repositories and mailing lists in a single request. Since hub ties all of the services together, this will be a very good thing to have before we proceed with its API! This will also bring many improvements we&rsquo;ve had planned for a long time, but will also require many serious internal design changes to our software, so it will require some effort to thoroughly test &amp; validate them before rolling it out. Federation will also open some doors for long-requested features, such as linking resources like bug trackers back to the project they belong to.</p> <h1 id="hut">hut</h1> <p><a href="https://sr.ht/~emersion/hut/">hut</a> is a CLI tool for interacting with SourceHut&rsquo;s GraphQL APIs, and it usually doesn&rsquo;t make it into these updates because it&rsquo;s not considered a core service. However, I wanted to mention it today because I added support for exporting your account data with hut this month. The export uses standard formats which are as portable as possible, such as bare clones of your git repositories or mbox dumps of your mailing lists, which you can re-import into any git provider or mailing list software. Following this, I will be adding a similar &ldquo;import&rdquo; functionality to bring your data back into any other SourceHut instance. You can dump your account data locally, or queue up a build job to do it on our servers.</p> <p>Data autonomy is an important goal of the beta, so this also moves us forward towards our long-term goals. It is also one step towards unblocking features like account removal or renaming. Exciting stuff!</p> <h1 id="metasrht">meta.sr.ht</h1> <p>No major updates this month, but I have been working on some upcoming features to tease: an overhaul to the billing system.</p> <p><img src="https://l.sr.ht/wPDl.png" alt="Screenshot of the new billing UI"></p> <p>Some of the improvements which will be on offer include:</p> <ul> <li>New payment methods, such as iDEAL and SEPA direct deposit</li> <li>The ability to enable or disable automatic renewal</li> <li>More currencies to pay with</li> <li>Better payment method management &amp; invoicing</li> </ul> <p>This is a very complex overhaul, so it will take some time to be completed. I&rsquo;m not sure when you can expect it to be released, but I&rsquo;m looking forward to shipping it to you!</p> <h1 id="buildssrht">builds.sr.ht</h1> <ul> <li>Alpine 3.16 is now available</li> <li>NixOS 22.05 is now available</li> <li>FreeBSD 13.1 is now available</li> <li>Fedora 34 has been removed following its upstream deprecation</li> <li>NixOS 21.05 has been removed following its upstream deprecation</li> </ul> SourceHut is committed to making IRC better https://sourcehut.org/blog/2022-07-06-sourcehut-and-irc/ Wed, 06 Jul 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-07-06-sourcehut-and-irc/ <p>Internet Relay Chat (IRC) is a wonderful protocol with a 34-year history of helping free software, there at every step alongside the rise of the internet. Many real-time chat empires have risen and fallen during its tenure, some of them leaving behind lessons IRC might learn from. But even in its original form, IRC is a simple and beautiful protocol on top of which many independent, federated networks have been built, from simple line-oriented plain-text messages (mostly) adhering to open standards, and implemented with free software.</p> <p>IRC has held a special place in my heart and in the hearts of my collaborators at SourceHut, both within the company and in the broader community. We rely on it every day, professionally and socially, and we want to help it be the best it can be. We want this because we love IRC for what it is: simple. There are many other solutions we could invest in, some of which are doing great things for free software (such as Matrix), and some of which are not (such as Discord). But, IRC is by far the simplest and most open, and these essential traits are both compatible with our culture and something we wish to preserve.</p> <p>What can we do to make IRC better while honoring what makes it so good?</p> <p>Our work focuses on making IRC easier to use and more accessible to a broader audience of free software contributors. While I might personally be satisfied with Weechat in a terminal on my other monitor, many new programmers have different wants. And while I was happy running my IRC bouncer for many years, I can&rsquo;t exactly suggest that it is a good solution for IRC&rsquo;s problems.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p> <p>The most obvious contribution to IRC from SourceHut is <a href="https://man.sr.ht/chat.sr.ht/">chat.sr.ht</a>, our hosted IRC bouncer which provides a &ldquo;just works&rdquo; IRC bouncer for SourceHut users. A pleasant webchat (<a href="https://sr.ht/~emersion/gamja/">gamja</a>, GNU AGPL 3.0) offers a jump-in-and-go experience, and our bouncer backend (<a href="https://sr.ht/~emersion/soju/">soju</a>, also AGPL) provides a scrollback, automatic log keeping, multi-device synchronization, and many other useful features that close most of the usability gap for IRC. The maintainer of these projects, Simon Ser, is also developing a new Android app for IRC (<a href="https://sr.ht/~emersion/goguma/">goguma</a>, (also AGPL)). Importantly, chat.sr.ht is not a new IRC network: we just facilitate access to independently operated and governed networks like Libera Chat and OFTC.</p> <p>chat.sr.ht is the face of SourceHut&rsquo;s IRC work, but there&rsquo;s also a lot of work you don&rsquo;t see. Simon is working with the IRCv3 community to improve IRC for everyone. Simon and others working on our stack have forwarded a half-dozen <a href="https://github.com/ircv3/ircv3-specifications/pulls?q=is%3Apr+author%3Aemersion">new IRC specifications</a> for review and standardization by the community, including support for push notifications, bouncer auto-configuration, and multi-device synchronization improvements. We also participated in the process of getting many other extensions standardized, such as chat history, account registration, and web socket support, and have offered <a href="https://github.com/ircdocs/modern-irc/pulls?q=is%3Apr+author%3Aemersion">many improvements</a> to the documentation at <a href="https://ircdocs.horse">ircdocs.horse</a>.</p> <p>Our approach is to make conservative, obvious improvements to IRC that close the usability gap without sacrificing the any of the things which we love about IRC. We believe in honoring and respecting our peers in the community, focusing on making the ecosystem stronger instead of seeking to make our foothold in it stronger. The fall of Freenode reminds us all of the importance of a healthy community of equal peers working to improve standards in the interests of us all, rather than in the interests of a small few. We&rsquo;re proud to do our part. #sr.ht was registered on Libera Chat only minutes after it opened and we were one of the first projects to make the move.</p> <p>I&rsquo;ve been using IRC for most of my life. It has played a crucial role in my social and professional life, playing its part in the success of many of my projects and in establishing many long-term friendships and professional relationships. Come add your voice with us in #sr.ht (on-topic) or in #sr.ht.watercooler (off-topic), both on Libera Chat. See you there :)</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>I might acknowledge, however, that many traits of the ephemeral discussions that stem from IRC&rsquo;s constraints are worth keeping even in the absence of these constraints. The lack of any expectation to scroll up and read the discussions you missed, and the cultural pressure to move important information out of chat and into more permanent mediums, like mailing lists or tickets, are two positive things that IRC&rsquo;s ephemeral nature encourages. As we move into a better world for IRC, let&rsquo;s be mindful of these things.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on SourceHut? June 2022 https://sourcehut.org/blog/2022-06-15-whats-cooking-june-2022/ Wed, 15 Jun 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-06-15-whats-cooking-june-2022/ <p>Hello everyone! Let&rsquo;s get straight into the news today. Our user count today is 29,612 users, of which 576 have joined since the last update. Remember to be patient with these new users as they learn the ropes. Welcome!</p> <h2 id="graphql">GraphQL</h2> <p>Adnan continues to ship GraphQL services for SourceHut, this month shipping webhooks for lists.sr.ht, and preparing to-be-reviewed patches adding webhooks to builds.sr.ht and paste.sr.ht. The latest GQL support matrix looks like this:</p> <dl> <dt>meta.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>git.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>hg.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>todo.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>builds.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks†</dd> <dt>lists.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>hub.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>paste.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks†</dd> <dt>pages.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks†</dd> </dl> <p>† To be added soon!</p> <p>The last major effort for the initial roll-out of GraphQL support will be hub.sr.ht. Following this, we will be experimenting with GraphQL federation, and starting to rewrite our cross-service communication to use GraphQL. We&rsquo;ll then make plans for sunsetting REST.</p> <h2 id="listssrht">lists.sr.ht</h2> <p>We are preparing some changes to mailing list visibility to bring it inline with the design of other services. Permissions will be consolidated into a single default set, and a &ldquo;visibility&rdquo; parameter will be added which matches the behavior of other services. Sane defaults for these new configurations will be selected based on your current configuration — you will have received an email if your mailing list configuration may require manual attention during the migration.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Image updates:</p> <ul> <li>freebsd/13.1 is now available</li> </ul> <p>NixOS 22.05 will be available soon, and Fedora 34 will be removed soon.</p> What's cooking on SourceHut? May 2022 https://sourcehut.org/blog/2022-05-16-whats-cooking-may-2022/ Mon, 16 May 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-05-16-whats-cooking-may-2022/ <p>Hello everyone! We&rsquo;re back at it for another month of news in the SourceHut sphere. Of our now 29,036 users, 630 are new this month: please offer them a warm welcome, and your patience, as they learn about the new platform.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Comprehensive GraphQL-native webhooks shipped for todo.sr.ht this month.</p> <p>Here&rsquo;s the latest GraphQL support break-down:</p> <dl> <dt>meta.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>git.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>hg.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>todo.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>builds.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>lists.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>hub.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>paste.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>pages.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> </dl> <p>We&rsquo;re getting there! The remaining webhooks should be fairly straightforward — lists will be the most complex of these — and updating hub.sr.ht will be the last major project before we complete the initial GraphQL implementation. Following this we will be experimenting with GraphQL federation as well, and once we have an answer regarding federation, the GraphQL milestone will be complete, and we&rsquo;ll have taken the largest step towards the beta.</p> <h2 id="coming-improvements-to-hut">Coming improvements to hut</h2> <p>The <a href="https://sr.ht/~emersion/hut">hut</a> command-line tool provides programmatic access to the SourceHut GraphQL APIs. I have been working on support for a comprehensive data export via this tool recently, which will be followed by an equivalent data import tool. This will allow you to take your account data from sr.ht to another instance, or to an instance with compatible software — most of the exported data is in standard formats like bare git repos and mbox archives. This is also another step towards the data ownership goal of the beta, and will be followed soon by self-service account deletion and renaming — which also require the completion of the GraphQL APIs that are progressing apace.</p> <h2 id="listssrht">lists.sr.ht</h2> <p>The new <a href="https://sr.ht/~emersion/go-emailthreads">go-emailthreads</a> library was integrated into lists.sr.ht&rsquo;s GraphQL API, which is the next step for improving the heuristics used on the code review screen.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>Work is underway, some of which landed this month, to improve PGP support on SourceHut, expanding the suite of supported ciphers and making it more reliable. Additional changes are expected in the foreseeable future to handle PGP key expiration, notifying users when their key needs to be cycled.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Image updates:</p> <ul> <li>ubuntu/kinetic is now available</li> <li>ubuntu/jammy is now available</li> <li>fedora/36 is now available</li> </ul> <h2 id="pagessrht">pages.sr.ht</h2> <p>Users may now configure custom Cache-Control headers to tune their site performance.</p> What's cooking on SourceHut? April 2022 https://sourcehut.org/blog/2022-04-15-whats-cooking-april-2022/ Fri, 15 Apr 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-04-15-whats-cooking-april-2022/ <p>Hello! Another month of improvements rolls on by, and I&rsquo;m here to tell you all about them. In terms of site growth, we saw 510 new users join us, bringing our total to 28,406. As always, please be patient with our new peers as you help them learn about the site.</p> <h2 id="general-news">General news</h2> <p>This month we released our <a href="https://sourcehut.org/blog/2022-04-08-2021-financial-report/">annual financial report</a>. In summary, SourceHut is financially healthy. Feel free to browse the full report to get all of the details.</p> <p>We have been making excellent progress on the GraphQL initiative thanks to Adnan&rsquo;s help, and I anticipate that we will be able to put a bow on this sometime in the next couple of months.</p> <h2 id="hgsrht">hg.sr.ht</h2> <p>Work is underway on integrating improvements to the hg.sr.ht GraphQL API. The API is now writable, supporting all essential resource mutations, and GQL-native webhooks should be landing shortly.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Setting the oauth keys in your build manifest will now pre-configure your build environment for use with the <a href="https://sr.ht/~emersion/hut">hut</a> tool.</p> <p>Image updates:</p> <ul> <li>Plan 9 support has been fixed and improved thanks to Benjamin Riefenstahl</li> <li>FreeBSD 12.x has been updated to FreeBSD 12.3</li> <li>Alpine 3.11 was removed following its upstream deprecation</li> </ul> <h2 id="listssrht">lists.sr.ht</h2> <p>We have integrated the new <a href="https://git.sr.ht/~emersion/go-emailthreads">go-emailthreads</a> library with lists.sr.ht, which provides much better heuristics for parsing mail threads into trees. We will soon update the lists.sr.ht frontend to take advantage of this.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>The branch name is now included in the build tags when submitting pushes to builds.sr.ht. You may want to update your badge URLs if you use them.</p> <h2 id="pagessrht">pages.sr.ht</h2> <p>It is not available yet, but in the next few days we expect to merge support for configuring per-file cache behavior for your site.</p> SourceHut's 2021 Financial report https://sourcehut.org/blog/2022-04-08-2021-financial-report/ Fri, 08 Apr 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-04-08-2021-financial-report/ <p>In summary, SourceHut is financially healthy, profitable, and growing. We enjoyed substantial YoY growth between 2020 and 2021. SourceHut hired its third full-time software engineer, and with the help of the <a href="https://nlnet.nl/project/SourcehutGraphQL/">NGI0 Discovery fund</a> we had another developer join us to help with the GraphQL development work. We have a sustainable business model and sufficient capital with which to execute all of our planned expansions, such as a new European datacenter presence.</p> <p>We had previously published public financial reports quarterly, but preparing such reports is a time-consuming process, particularly given the growing complexity of our finances. Starting with this report, and going forward, we will publish reports annually. The exact format of these reports and the ability to compare numbers across years will be somewhat inconsistent as we gradually move our business operations into Europe.</p> <p><small>Disclaimer: this report is a summarized approximation of our financials, and is not used for tax purposes.</small></p> <h2 id="2021-revenue-sources">2021 revenue sources</h2> <p>SourceHut has two main revenue streams:</p> <ol> <li>Paid subscriptions for the forge platform, which are generally consistent</li> <li>Contracts via our <a href="https://sourcehut.org/consultancy/">consulting arm</a>, which are generally more inconsistent</li> </ol> <p>We use the forge platform revenue as the basis for our planning and treat consulting revenue as capital to fund new projects.</p> <h3 id="platform-revenue">Platform revenue</h3> <p>We issued 10,484 invoices to SourceHut subscribers in 2021. Subscriptions are available at three price points: $2, $5, and $10; billed monthly, or annually for a 2 month discount. Invoices paid in 2021 break down as follows:</p> <pre tabindex="0"><code>5,153 $ 2 (paid monthly) 2,098 $ 5 (paid monthly) 818 $10 (paid monthly) 1,672 $ 2 (paid yearly) 496 $ 5 (paid yearly) 184 $10 (paid yearly) </code></pre><p>The total revenue from platform subscriptions in 2021 was $105,777.08, which, after credit card processing fees, was $98,741.95. This is an increase of 35% over 2020. In 2021, a total of 7,184 new users signed up for an account. Of these users, 956 signed up for a paid account. Of these 956, 45 are currently delinquent. This is a conversion rate of 12.6%, slightly improved from 2020&rsquo;s 11.7%. Among all users registered in all years (a total of 28,262 at the time of writing), 11.35% (or 3,209 users) have paid accounts.</p> <p>This modest increase may be at least somewhat explained by the introduction of paid-only services such as builds.sr.ht and chat.sr.ht in 2021. Note that, following the completion of the alpha, all users who own resources (such as repositories, bug trackers, mailing lists, etc) will be expected to move to a paid account. Contributors will not be expected to pay, and users who wish to pay but cannot will be offered financial aid.</p> <p>On the subject of financial aid, at the time of writing, 59 users have received financial aid. 100% of users who requested financial aid received it. Reasons provided by users include, in descending order of frequency:</p> <ul> <li>Inability to pay due to financial constraints</li> <li>Lack of support for their preferred payment method</li> <li>Political sanctions due to the situation in Ukraine and Russia</li> </ul> <h3 id="consulting-revenue">Consulting revenue</h3> <p>SourceHut accepts consulting projects at the discretion of our full-time engineers, part-time. These contracts are executed in public and are required to only produce free and open source software.</p> <p>In total, SourceHut received $285,739 in revenue from consulting engagements in 2021.</p> <h3 id="summary-of-revenue">Summary of revenue</h3> <p>Our total revenue from all sources for 2021, before taxes, expenses, and fees, was $391,516.</p> <h3 id="cash-on-hand">Cash on hand</h3> <p>At the close of the year, we had $102,402 in cash on hand.</p> <h2 id="2021-expenses">2021 expenses</h2> <p>In 2021 we had the following expenses, excluding payroll:</p> <pre tabindex="0"><code>$8,277 Colocation costs (space, power, network) $7,035 Credit card processing fees $2,125 Sponsorships $1,110 Domain names $ 995 Miscellaneous $ 570 Insurance </code></pre><p>We cancelled our GitHub sponsorships partway through the year, and began sponsoring the OpenStreetMap project as a Bronze sponsor.</p> <p>From 2022 forward, we use a standard approach to compensation. Each full-time SourceHut engineer earns $2,500 per month for self-directed work furthering our mission to &ldquo;make free software better&rdquo; at their own discretion; working on projects like the forge but also maintaining independently directed projects and contributing to the broader ecosystem. Additionally, SourceHut engineers can elect to, at their discretion, participate part-time (generally no more than two days per week) on consulting projects. Furthermore, my compensation as CEO was dealt with separately — previously I made a bit less than everyone else, and going forward I will also be paid the standard compensation.</p> <p>In 2021, our compensation scheme was not standardized, and varied throughout the year. We also had three special personnel arrangements in 2021: one paid intern, one short-term, part-time contractor to help with a specific internal project, and one medium-term, part-time contractor to help with a specific consulting engagement. For privacy reasons, and due to the complexity of the situation, we will report our compensation figures in aggregate. In 2022, we will break this figure down further for transparency.</p> <p>Not including my compensation as CEO, we paid a total of $131,597 between all forms of staff compensation.</p> <p>Thus, our total expenses for 2021 were $151,459.</p> <h2 id="2021-financial-summary">2021 financial summary</h2> <dl> <dt>Revenue</dt> <dd>$391,516</dd> <dt>Expenses</dt> <dd>-$151,459</dd> <dt>Taxes</dt> <dd>-$50,000 (approx)</dd> <dt>Profit</dt> <dd>$189,000 (approx)</dd> </dl> <h2 id="expectations-for-2022">Expectations for 2022</h2> <p>We have three full-time staff paid under the standard compensation model, and about $700/mo in recurring expenses. Currently we make about $9200/mo from the platform, putting our monthly profit at about $1000, without factoring in consulting revenue. Thus, the platform provides for a sustainable business independently of our other lines of business. The breakdown of active subscriptions at the time of writing is as follows:</p> <pre tabindex="0"><code>$2 monthly 518 users $5 monthly 210 users $10 monthly 80 users $2 yearly 1,710 users $5 yearly 500 users $10 yearly 190 users </code></pre><p>We have three ongoing consulting contracts which we expect to continue through most of the year. We have already migrated or established some of these contracts with the new Dutch business entity, and we intend to migrate more of our business over the Atlantic throughout 2022.</p> <p>At the time of writing, SourceHut has $62,608 and €30,590 in cash on hand.</p> <p>The only major investment we have planned is the deployment of a European datacenter presence, which is likely to begin in late 2022, but may be delayed to early 2023.</p> <h2 id="conclusion">Conclusion</h2> <p>In short, SourceHut is profitable and is comfortably succeeding in its efforts to provide sustainable software development &amp; infrastructure for the free and open source software community. We remain committed to investing 100% of our profit into the free and open source community. I want to extend my thanks to the SourceHut community for its role in achieving our goals: sincerely, thank you.</p> What's cooking on SourceHut? March 2022 https://sourcehut.org/blog/2022-03-15-whats-cooking-march-2022/ Tue, 15 Mar 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-03-15-whats-cooking-march-2022/ <p>Today we celebrate another 487 new members who&rsquo;ve joined since our last update, bringing our community to 27,896 users in total. As always, I&rsquo;m relying on you to be patient with them as they learn the ropes and to make sure they feel welcome here. This month saw many improvements, but much of them were internal changes or bug fixes, so this update will be somewhat short.</p> <p>The Mumble meeting for this month is again cancelled, as the call for agenda items returned no answers. Going forward, we will set up meetings only for specific discussions, such as future discussions on billing changes for the alpha to beta transition.</p> <h2 id="general-news">General News</h2> <p><a href="https://lists.sr.ht/~sircmpwn/sr.ht-admins/%3CCI1WEI9N6SXZ.L6YK21RIRDUE%40taiga%3E">SourceHut for Alpine Linux 3.15</a> is now available, and the 3.14 repository is no longer maintained. Self hosters are encouraged to upgrade at their earliest convenience.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>It is now possible to create new repositories by <a href="https://git.sr.ht/clone">cloning them from an existing git URL</a>.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Alpine 3.11 has been removed following its deprecation upstream. Issues with 9front builds have also been corrected, and further Plan 9 improvements are underway.</p> What's cooking on SourceHut? February 2022 https://sourcehut.org/blog/2022-02-15-whats-cooking-february-2022/ Tue, 15 Feb 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-02-15-whats-cooking-february-2022/ <p>Hello again! Today is a rare sunny and beautiful day in Amsterdam, and I am spending it inside writing this post with the blinds down, as is befitting of a proper hacker. I&rsquo;m pleased to welcome 529 new users to our service this month, who together bring our community to 27,409 members. I hope our new members are enjoying the service, and that our existing community does its part to make them feel welcome.</p> <p>This month&rsquo;s Mumble meeting will not take place, as the <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CCH8QXZ08BYJ3.3H23LG5R594XS%40megumin%3E">call for agenda items</a> went unanswered. Please add topics to the <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CCHWKTDCPKRAY.WK9EW0VG9AHU%40taiga%3E">March agenda</a> if you wish to address any matters in next month&rsquo;s meeting.</p> <h2 id="new-staff-v2">New staff v2</h2> <p>Last month, I introduced Adnan Maolood, who, thanks to a generous sponsorship from NLNet, will be working with us on GraphQL for a while. This month, I am pleased to <a href="https://sourcehut.org/blog/2022-02-02-welcome-conrad/">introduce Conrad Hoffmann</a>, who joins us as the latest full-time free software engineer working on SourceHut. Check out the blog post to meet him!</p> <h2 id="todosrht">todo.sr.ht</h2> <p>After many delays, the todo.sr.ht writable GraphQL API has finally shipped! Thank you for your patience. The documentation is <a href="https://man.sr.ht/todo.sr.ht/graphql.md">available here</a> and you can play with it directly on the <a href="https://todo.sr.ht/graphql">todo GraphQL playground</a>.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>Adnan&rsquo;s first batch of GraphQL improvements landed yesterday as we shipped support for GraphQL-native webhooks in git.sr.ht alongside a number of other improvements. Nice work, Adnan! Adnan will continue with more GraphQL improvements for other services in the next few weeks.</p> <h2 id="pagessrht">pages.sr.ht</h2> <p>One of Conrad&rsquo;s first contributions to SourceHut introduced Content-Encoding support and compression which, together with improvements from Umar Getagazov, should make the performance of SourceHut pages noticably better. Dhruvin Gandhi also added support for custom 404 pages. Great work, everyone!</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Image updates:</p> <ul> <li>ubuntu/hiruste has been removed following its upstream deprecation</li> <li>Fedora images now include dnf-plugins-core by default</li> </ul> <p>Improvements are also underway for Guix and Plan 9 support. Thanks to Haowen Liu, Ryan Gonzalez, Dhruvin Gandhi, and Benjamin Riefenstahl for their work in these areas.</p> <h2 id="namessrht">names.sr.ht</h2> <p>More community members have been expressing interest in working on names.sr.ht as a grassroots, community-led effort. Conrad has set up <a href="https://sr.ht/~bitfehler/names.sr.ht/">a project</a> to organize these efforts, and I have posted <a href="https://lists.sr.ht/~bitfehler/names.sr.ht-discuss/%3CCHVUXZKXJJ4C.NB3VSS2CBXE1%40megumin%3E">a summary of my thoughts</a> to offer some direction. Please get involved if this interests you!</p> <h2 id="other-news">Other news</h2> <p>A quick &ldquo;thanks!&rdquo; is owed to Ignas Kiela for his continued work on improving SourceHut&rsquo;s monitoring infrastructure this month. Thanks to his work on our web services, we have sane data available for response codes like 500 errors and alarms configured to alert us when they occur in volume.</p> <p>Another quick shout-out to the emacs community, who, in the process of evaluating SourceHut for their needs, sent a dozen or so patches improving lists.sr.ht, particularly with respect to importing third-party mbox archives. Many thanks!</p> Welcoming Conrad Hoffmann, the newest SourceHut developer https://sourcehut.org/blog/2022-02-02-welcome-conrad/ Wed, 02 Feb 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-02-02-welcome-conrad/ <p>I&rsquo;m pleased to introduce the SourceHut community to Conrad Hoffmann, aka bitfehler, who joins us this month as SourceHut&rsquo;s third full-time FOSS developer. Like the rest of our full-time staff, Conrad&rsquo;s role is to do self-directed work to &ldquo;make FOSS better&rdquo; per the mission of SourceHut, and in addition to working on the forge, Conrad will be working with many FOSS projects in the community, including projects on SourceHut and in the FOSS ecosystem as a whole.</p> <p>Conrad is a Berliner whose introduction to FOSS came from his experience with SUSE Linux during his mandatory military service. He fell in love and started contributing to projects like KDE and heading down a career path which brought him deeper into Linux and the FOSS ecosystem, learning to use (and enjoy) the C programming language in particular. Conrad&rsquo;s last job was at SoundCloud, where he contributed to HAProxy and bore witness to the birth of <a href="https://prometheus.io">Prometheus</a>, which eventually became the basis for <a href="https://metrics.sr.ht">SourceHut&rsquo;s own monitoring at metrics.sr.ht</a>.</p> <p>In his role at SourceHut, Conrad will keep maintaining his Prometheus exporters and will branch out into a number of new interest areas. His experience with ops and infrastructure is something we&rsquo;re hoping to utilize when setting up the European datacenter, and he&rsquo;s also interested in joining the community efforts towards building a SourceHut DNS service. We can also expect some interesting things from Conrad in the Pine64 and OpenStreetMap communities, both of which have received funding and support from SourceHut in the past. He also intends to make a difference at a local level as his newborn daughter grows up in a society run by commercial proprietary software by advocating for the adoption of FOSS in schools and other places in his community.</p> <p>I am very pleased to have Conrad on board at SourceHut, and I&rsquo;m looking forward to working with him. I hope that you, members of the SourceHut community, will offer him your welcome as well as he begins to work on projects on SourceHut and in the broader FOSS ecosystem. He invites you to reach out and get to know him:</p> <blockquote> <p>I am bitfehler on libera.chat, you can find me in the #sr.ht.watercooler channel or message me if you feel like chatting!</p> </blockquote> <p>Please say hello! Welcome to SourceHut, Conrad!</p> What's cooking on SourceHut? January 2022 https://sourcehut.org/blog/2022-01-17-whats-cooking-january-2022/ Mon, 17 Jan 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-01-17-whats-cooking-january-2022/ <p>Hello and happy new year! After a bit of well-deserved rest during the holidays, our staff (and many of our contributors) have spun our work streams back up and development continues. Our userbase has grown this month by another 634 users, bringing the total to 26,880. As usual, I&rsquo;m depending on you to make our new members feel welcome and to offer them your patience as they learn how we do things here.</p> <p>This month’s public Mumble meeting will take place tomorrow, January 18th (later than originally announced), at 10:00 UTC in the usual place, voice.mnus.de in the sourcehut room. I called for suggestions for an agenda on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CCGGODWFWKK0G.3EKBVZZM5KMRA%40taiga%3E">sr.ht-discuss</a> — now would be an opportune time to add your own suggestions if you haven’t already.</p> <h2 id="new-staff">New staff</h2> <p>I <a href="https://sourcehut.org/blog/2022-01-10-nlnet-graphql-funding/">announced last week</a> that, thanks to a generous grant from NLNet, Adnan Maolood will be joining us for a while this year to help with the GraphQL implementation. He&rsquo;s been hard at work on git.sr.ht&rsquo;s GraphQL-native webhooks already, and I&rsquo;m looking forward to having his help. Welcome! We are also bringing on a new full-time employee (at SourceHut&rsquo;s expense) from February 1st, who will be introduced in a coming blog post.</p> <h2 id="hut-a-sourcehut-cli-tool">hut: A SourceHut CLI tool</h2> <p>Simon Ser has started developing a command line tool called <a href="https://sr.ht/~emersion/hut">hut</a> for using the GraphQL API in your terminal or in shell scripts. Check it out!</p> <h2 id="todosrht">todo.sr.ht</h2> <p>I had hoped to ship todo.sr.ht&rsquo;s GraphQL API this week, but its inherent complexity combined with time off during the holidays has pushed the schedule back a bit more once again. All that remains is the completion of the legacy webhooks for the writable API, plus acceptance testing and a security review, then we can ship. This should land sometime this week, if everything goes according to plan.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>Adnan has been working on GraphQL-native webhooks for git.sr.ht, which is going well. This will also hopefully ship before the next &ldquo;what&rsquo;s cooking&rdquo;.</p> <h2 id="listssrht">lists.sr.ht</h2> <p>A number of long-standing bugs when importing mbox files to populate mailing lists from an external archive have been addressed thanks to contributions from Martin Vahlensieck. Thanks Martin! A number of small fixes and improvements to the GraphQL schema were also introduced this month.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>Some discrepancies between our OAuth 2.0 implementation and the RFC were discovered and corrected. Thanks to ~omz13 for the tip!</p> SourceHut selected for NLNet NGI Zero funding https://sourcehut.org/blog/2022-01-10-nlnet-graphql-funding/ Mon, 10 Jan 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-01-10-nlnet-graphql-funding/ <p>I&rsquo;m pleased to share that SourceHut has been selected by <a href="https://nlnet.nl">NLNet</a> to receive funding as part of the <a href="https://nlnet.nl/discovery">NGI Zero: Search &amp; Discovery</a> fund for the purpose of completing API 2.0, our GraphQL API development. NLNet is providing monetary support to SourceHut contributor Adnan Maolood, aka <a href="https://sr.ht/~adnano">~adnano</a>, who has agreed to work full-time to help with our API 2.0 efforts over the course of this year.</p> <p>The NLNet Foundation is a Dutch organization which provides funding to various projects which promote open and secure digital infrastructure, and has provided funding for <a href="https://nlnet.nl/project/current.html">hundreds of free and open-source projects</a>, many of which you rely on every day, and some of which rely on SourceHut! Prior recipients of NLNet funding include projects like Tor, WireGuard, postmarketOS, Jitsi, and more, and I&rsquo;m proud to see SourceHut join them.</p> <p>API 2.0 is one of the major outstanding tasks between us and the completion of the SourceHut beta. We can look forward to much better access to SourceHut&rsquo;s internals, a more robust implementation, and a simpler deployment system for third-party SourceHut installations. We&rsquo;ll be building upon this work to develop alternative frontends, such as the <a href="https://sr.ht/~emersion/hut">hut</a> CLI tool and a new <a href="https://gemini.circumlunar.space">Gemini</a>-based frontend. This also paves the way for many other features which we&rsquo;re cooking up, including user groups/organizations, better data autonomy tools for import &amp; export and account deletion &amp; renaming, and future plans like names.sr.ht&rsquo;s DNS hosting and domain registration services. Exciting stuff!</p> <p>I&rsquo;m excited for this initative, and I&rsquo;m glad to have Adnan on board to help. Big thanks to NLNet for agreeing to sponsor his work! Let&rsquo;s get this beta done.</p> How does SourceHut's FOSS business model work? https://sourcehut.org/blog/2022-01-09-how-does-our-business-work/ Sun, 09 Jan 2022 00:00:00 +0000 https://sourcehut.org/blog/2022-01-09-how-does-our-business-work/ <p>SourceHut makes a profit, but we are not motivated by profit. I founded SourceHut with the explicit goal of making my free software work sustainable full-time. As SourceHut grows, we aim to expand and generalize this approach. We want to make free software better, and the business is a tool we use to facilitate this.</p> <p>We have two lines of business which provide us with revenue: the SourceHut software-as-a-service (SaaS) platform, and free software consulting. You can run the SourceHut platform yourself (<a href="https://man.sr.ht/installation.md">instructions are available here</a>), but it&rsquo;s expensive and time consuming to maintain the platform, so most people pay us to do it for them via monthly or annual subscription fees. This model sets up incentives which favor users over investors,<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> which gives us an honest focus on user-motivated design (as opposed to profit-motivated design) and ensures that we are dis-incentivized to use unethical means to make our margin, such as selling your personal information. Your payments also provide for the development and maintenance of the service, which we try to honor by ensuring reliable uptime &amp; performance, comprehensive backups, and so on, via a robust operational strategy which is not economically practical for small-scale deployments.</p> <p>Our second line of business is free software consulting. Free software has eaten the world: it is ubiquitous in all software products. This has created a market for free software experts who have a broad understanding of the free software ecosystem and experience working upstream. We provide consulting services to this market, in which we are paid to write or contribute to free software. Upstream projects we&rsquo;ve worked on under this model includes software like <a href="https://kernel.org">Linux</a>, <a href="https://mesa.freedesktop.org/">Mesa</a>, <a href="https://x.org/wiki/">X.org</a>, <a href="https://monado.dev/">Monado</a>, and many others, for clients like <a href="https://www.valvesoftware.com/en">Valve Software</a>, <a href="https://status.im/">Status.im</a>, and <a href="https://www.migadu.com/">Migadu</a>. We have also developed greenfield software for these clients, such as <a href="https://sr.ht/~migadu/alps/">alps</a>, <a href="https://git.sr.ht/~bl4ckb0ne/wxrc">wxrc</a>, and <a href="https://github.com/plagman/gamescope">gamescope</a>, as well as improvements to software which our team maintains independently, such as <a href="https://gitlab.freedesktop.org/wlroots/wlroots">wlroots</a> or <a href="https://wayland.freedesktop.org/">Wayland</a>.</p> <p>We use the revenue from these lines of business to fund free software projects through the work of our full-time employees, of which there are two: myself and Simon Ser. We work at our discretion on free software projects, some of which are not obviously monetizable, for the purpose of making the free software ecosystem stronger as a whole. Sometimes this work ultimately provides revenue — for example, Simon&rsquo;s <a href="https://sr.ht/~emersion/soju">soju</a> and <a href="https://sr.ht/~emersion/gamja">gamja</a> projects were developed independently and eventually were incorporated into the paid <a href="https://sourcehut.org/blog/2021-11-29-announcing-the-chat.sr.ht-public-beta/">chat.sr.ht</a> product. We also developed <a href="https://gitlab.freedesktop.org/wlroots/wlroots">wlroots</a> together (starting before SourceHut was founded), which eventually was the basis of much of our consulting revenue. However, it&rsquo;s more common that these projects don&rsquo;t produce a return.</p> <p>Many of our projects have no profit motive and are probably unmonetizable. Our mission is to make free software better, profitable or not. Projects like <a href="https://sr.ht/~sircmpwn/visurf/">visurf</a> or <a href="https://gemini.circumlunar.space">gemini</a>, our upcoming <a href="https://drewdevault.com/2021/03/19/A-new-systems-language.html">systems programming language</a>, upstream work in <a href="https://alpinelinux.org">Alpine Linux</a> or <a href="https://www.freedesktop.org/wiki/">freedesktop</a>, or sponsorship of projects like <a href="https://wiki.osmfoundation.org/wiki/Corporate_Members#Bronze_Corporate_Members">OpenStreetMap</a> — none of these have obvious returns for us. We work on them because we believe that they are important. If we were pressed to justify this in business terms, we might say that we are growing the free software market as a whole through this work, or that they are good for marketing (both of which are true), but fundamentally it&rsquo;s because we believe in free software.</p> <p>We will be hiring a third full-time engineer in February, who we will introduce to you when the time comes. Following our tradition of transparency, you&rsquo;re welcome to read the <a href="https://man.sr.ht/staff/culture.md">onboarding manual</a> we have prepared for them, which goes into more detail on what it&rsquo;s like to work for SourceHut. We also occasionally bring on temporary workers to work within specific goals. For example, thanks to an <a href="https://nlnet.nl/project/SourcehutGraphQL/">NLNet sponsorship</a>, we will have Adnan Maolood on for the year to help with the GraphQL work. We have also hired contractors for things like consulting work, or for help with some of our independent FOSS projects or upstream needs.</p> <p>This is how we do business. Does it work?</p> <p>In short: yes. We will answer this question in great detail in our coming annual financial report,<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> but I can summarize it for you now. The books for 2021 are not quite closed yet, but it looks like we&rsquo;re going to end up in the vicinity of half a million dollars in gross revenue, which I think is pretty damn good for a bootstrapped company in its third year, especially one which gives away 100% of the software it builds free of charge.</p> <p>There are many ways to finance free software. This is our way, and it works. We fund improvements to hundreds of free software and free culture projects, many which would be otherwise impossible to do profitably or even sustainably. All of our profit has been or will be invested strictly in free software and free culture projects, most of which are not even maintained by us. There&rsquo;s no &ldquo;open core&rdquo; going on here: every line of code we write is genuine free-as-in-freedom software.</p> <p>I&rsquo;m very proud of what we&rsquo;ve built.</p> <p>We built it with your help. Many SourceHut community members have taken on serious roles in our projects, contributing heaps of code to every project, even maintaining some subsystems, or occasionally entire sourcehut services like hg.sr.ht, in their spare time. We have had community contributions to thank for many improvements in functionality, reliability, documentation, and more. Even the simple choice to host your projects with us is an investment in our community, and one which can be difficult to make against the temptations of more popular nonfree or semi-nonfree platforms in the market like GitHub or GitLab. I am grateful to everyone who has had a hand in this success. Thank you.</p> <hr> <p>Making free software better means making it better for everyone, not just us. We want to make free software profitable for <strong>you</strong>, too. One of our upcoming products is &ldquo;hire.sr.ht&rdquo;, which will provide an index of independent free software contractors to solicit clients.</p> <p><a href="https://l.sr.ht/o31H.jpg"><img src="https://l.sr.ht/o31H.jpg" alt="Mock-up of a profile on this service"></a></p> <div class="caption">(click to enlarge)</div> <p>I hope to see this platform used for a variety of free software work. It could be weekend hackers who maintain some projects in their spare time and get paid by users to implement the features they want, or weekend hackers who get paid by users to send patches to <em>other</em> projects. Or, you could be working on a FOSS project of your own and hire someone with a relevant skillset to help you get it started. Maybe we&rsquo;ll see full-time free software consultants listed here, taking on larger long-term engagements to work on free software for businesses, or even free software consultancy co-ops or businesses like SourceHut itself.</p> <p>We plan on offering this service as part of your normal sourcehut subscription fee,<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> without taking any commissions or trying to control the line of communication between you and your clients. You will write your own contracts, negotiate with clients directly, handle billing and payments without our involvement, and retain complete and independent ownership over your work and client relationships. We will support you in figuring these things out, and I hope to see an organic community of mutual support form between contractors (and clients) to provide these things for each other, without tying your livelihood up under SourceHut&rsquo;s control.</p> <p>Like the rest of SourceHut, this is an open source project, and we&rsquo;re developing it <em>with</em> you as much as we are developing it <em>for</em> you. We could use your help in building this. If you&rsquo;re interested in working on this project, please <a href="mailto:[email protected]">reach out</a>. There&rsquo;s also a grassroots community project to build out domain registration and DNS hosting services on SourceHut which could use your help. If you have any other ideas, I want to hear them. If you have time, passion, and ideas, we&rsquo;ve got servers and a community. Let&rsquo;s talk.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>Which we don&rsquo;t have. Investors, that is.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>If you&rsquo;re wondering where these went, this is the answer. They&rsquo;re too much work to do quarterly, especially as our business situation was complicated by the recent introduction of a Dutch business entity and our growing consulting revenue. Sorry that these stopped for a while! I will write up the next one soon.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:3"> <p>Including for users who need financial aid and rely on our subsidized or free subscriptions.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on SourceHut? December 2021 https://sourcehut.org/blog/2021-12-15-whats-cooking-december-2021/ Wed, 15 Dec 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-12-15-whats-cooking-december-2021/ <p>Hello and happy holidays! I hope that our 26,246 member userbase is enjoying the cold weather (or the warm weather, in the south). Remember to remind the people you work with on SourceHut, and others besides, that you care about them. We have many new users this month, and I hope you will extend them the same kindness and patience which you remember from your own first steps on SourceHut.</p> <p>This month&rsquo;s public Mumble meeting will take place tomorrow at 10:00 UTC in the usual place, voice.mnus.de in the sourcehut room. This time, I called for suggestions for an agenda on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CCFXVLXTHGFRT.SDU03YTQ98E%40taiga%3E">sr.ht-discuss</a> — now would be an opportune time to add your own suggestions if you haven&rsquo;t already.</p> <h2 id="chatsrht">chat.sr.ht</h2> <p>Towards the beginning of this month, <a href="https://sourcehut.org/blog/2021-11-29-announcing-the-chat.sr.ht-public-beta/">we announced chat.sr.ht</a>, a hosted IRC bouncer for SourceHut users. Please give it a shot if you haven&rsquo;t yet. Simon has been hard at work improving it further still since the launch, and mainly making improvements to usability and fixing bugs. The next major development will be the introduction of the REGISTER extension, which we will follow-up on by writing patches for the rest of the IRC ecosystem to help nudge adoption along, alongside <a href="https://github.com/ircv3/ircv3-specifications/pulls/emersion">our other IRC standardization work</a>.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Thanks to Robin Jarry&rsquo;s patches, you can now reference and close tickets on todo.sr.ht from your git.sr.ht commits using standard git trailers. Check out <a href="https://man.sr.ht/git.sr.ht/#referencing-tickets-in-git-commit-messages">the docs</a> for details. Robin was very patient with my demands for this patchset — thanks Robin!</p> <p>Ignas Kiela has also taken it upon themselves to spend more time improving SourceHut monitoring and performance, landing patches throughout SourceHut this month to improve our metrics and using the information derived from these improved metrics to guide his work in todo.sr.ht patches. Thanks, Ignas, keep it up!</p> <p>The planned writable GraphQL API release for todo.sr.ht is taking longer than anticipated, and will require a couple more weeks still. todo.sr.ht is one of the most complex services on SourceHut, and getting every little interaction right is a fair bit of work. It&rsquo;s not helped by the fact that we&rsquo;re slowing down a bit to rest at the end of the year — sorry for the wait.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>You can now upload more than one artifact to a git tag at the same time. Adnan Maolood has also helped to refine the <a href="https://sr.ht/~ancarda/vcs-autodiscovery/">vcs-autodiscovery</a> specification, alongside ~ancarda, and implemented it both in git.sr.ht and godocs.io, to provide a standard means of accessing forge-related metadata for git repositories.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Image updates:</p> <ul> <li>nixos/21.11 is now available, and 20.09 has been removed</li> </ul> An interview with 100 rabbits https://sourcehut.org/blog/2021-12-08-100-rabbits-interview/ Wed, 08 Dec 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-12-08-100-rabbits-interview/ <p><a href="https://100r.co/site/home.html">Hundred Rabbits</a> is an artistic duo hacking their way around the Pacific on their sailboat. I invited them to sit down for an interview to talk about about their lifestyle, art, philosophy, and their <a href="https://sr.ht/~rabbits/">SourceHut projects</a>. This interview was conducted live in the #sr.ht.watercooler IRC channel on Libera Chat.</p> <p><em>Drew: Hi Devine! Happy birthday, Rek!</em></p> <p><strong>Rekka</strong>: Haha, thanks!</p> <p><em>Devine waves</em></p> <p><em>Drew: Would you two introduce yourselves?</em></p> <p><strong>Rekka</strong>: We are two artists who live and work on a sailboat named Pino. We traveled around the Pacific Ocean for 5 years, learning about technological resilience. I am an illustrator, but I also write, and Devine is a programmer that also makes music.</p> <p><em>Drew: Why live at sea?</em></p> <p><strong>Devine</strong>: We don&rsquo;t live at sea: we live on the water, near the coasts, and sometimes we traverse large spans of ocean. We chose to live on a boat so we could go where the wind would take us. We quickly look for shelter when we can and try to limit the time we spend at sea to a minimum.</p> <p><em>Drew: That makes sense. The sea intimidates me, to be honest.</em></p> <p><strong>Devine</strong>: Us, too.</p> <p><em>Drew: Have you found your boating lifestyle to be a good platform for the art projects you build?</em></p> <p><strong>Rekka</strong>: Yes, definitely. We find that we work really well with constraints.</p> <p><strong>Devine</strong>: A lot of our projects are advised by the extreme position in which we find ourselves, away from internet connectivity and one-day delivery networks.</p> <p><em>Drew: Projects like?</em></p> <p><strong>Rekka</strong>: We&rsquo;re always working on our wiki, it&rsquo;s the project we update the most. We document everything we learn like food preservation, boat repairs, places we&rsquo;ve been, etc.</p> <p><em>Drew: I like that community-building mindset very much, Rek.</em></p> <p><strong>Devine</strong>: The energy we collect from the sun dictates the number of cycles our software can use to run, and how much time we can dedicate on working on the computer to build them. This has ruled out a lot of modern technologies, it&rsquo;s also what brought us here, to be using SourceHut in the first place.</p> <p><em>Drew: I imagine that the energy constraints are also why many of your projects involve stepping away from the computer, like food preservation and log-keeping.</em></p> <p><strong>Devine</strong>: If we can use less technology to solve any one task, we will. Our ideal amount of technologies is <u>as little technology as possible</u>.</p> <p><em>Drew: You&rsquo;ve led me to another question I wanted to ask: how does SourceHut fit into your workflow?</em></p> <p><strong>Devine</strong>: Our work is done almost entirely offline, but when we do have connectivity, we&rsquo;re looking for building mirrors of our work for redundancy. As much as people like to throw the words &ldquo;why don&rsquo;t you self-host&rdquo; at us, having someone making sure that our repos are available while we&rsquo;re days or weeks away from shore is what keeps our projects alive and gives us peace of mind.</p> <p><em>Drew: I cannot imagine a boat in the middle of the Pacific making for a good place to host a server. Did you try any other platforms before settling on SourceHut?</em></p> <p><strong>Rekka</strong>: We were on GitHub for a few years.</p> <p><em>Drew: How does it compare?</em></p> <p><strong>Devine</strong>: It&rsquo;s hard to put into words, there&rsquo;s a general trend in software right now to compete for attention and skew people&rsquo;s behavior to act in favor of large ecosystems. GitHub is heavily afflicted by that sickness. SourceHut, less so.</p> <p><em>Drew: Sick of manipulative corporate behavior?</em></p> <p><strong>Devine</strong>: Yep, that&rsquo;s the word I was looking for.</p> <p><em>Drew: I admire the Rabbits for similar reasons: you have this down-to-earthness that I can connect with.</em></p> <p><em>Drew: In more practical terms, do you find the lightweight approach to SourceHut&rsquo;s UI design to be easier on your power and bandwidth constraints?</em></p> <p><strong>Devine</strong>: It&rsquo;s worlds apart. Because we work entirely from donated second-hand devices, backward compatibility is more important to us at this point. In our eyes, better software is software that gets smaller over time, that sheds the superfluous, and that reaches further backward in time for that onto which it can run. SourceHut appealed to us instantly because there are so few examples of this willingness to reduce consumption in the wild.</p> <p><em>Drew: I use a 12 year old laptop myself. I think it&rsquo;s also important to recognize that the ability to recklessly consume is a privilege that not everyone has, and you&rsquo;re locking out a lot of users by only designing for the latest and greatest. Even in FOSS, it can be a challenge to get people on board with that philosophy.</em></p> <p><strong>Devine</strong>: That&rsquo;s definitely a big part of this. You can only call yourself anti-capitalistic for so long while also catering only to people with the latest gizmos.</p> <p><em>Drew: On the subject of FOSS, why did you choose to release your software works as free (as in freedom) software, and your artistic works with Creative Commons?</em></p> <p><strong>Rekka</strong>: We don&rsquo;t want our projects to die with us.</p> <p><strong>Devine</strong>: We can&rsquo;t be there for people, we&rsquo;re at sea for months at a time. The code has to speak for itself, be inspectable and repairable without our being there. We cannot sell our works as services, because we&rsquo;re never there for people who might need our help fixing it.</p> <p><strong>Rekka</strong>: And things can happen at sea&hellip; as grim as it is to say that.</p> <p><strong>Devine</strong>: During every long passage we consider that we might have pushed our last commit, and is that the final state of this idea, possibly not. We like to think that someone might pick up our work where it was left.</p> <p><em>Drew: That speaks to an admirable level of attentiveness to the needs of your users. And FOSS is a good way to cement your legacy.</em></p> <p><em>Drew: May I ask what motivates your work? Why these projects? Why software as art? Why illustrations?</em></p> <p><strong>Rekka</strong>: The two of us like to create worlds. And art is a way is a way to do that.</p> <p><strong>Devine</strong>: Software is a way to make that world-building interactive and invite people into these worlds.</p> <p><em>Drew: Do you view your work as having more of a performative or collaborative nature?</em></p> <p><strong>Devine</strong>: We obviously don&rsquo;t share the same limitations as most. While I think people like our general philosophy, we will not convince Ubisoft to start making Dreamcast games. To most people, we&rsquo;re exploring a fork in the road. The emulation scene constantly offers a reminder of what-if&hellip; what if Plan 9 had been picked up, what if Genera, what if&hellip; Art does this sort of exploration better than anything else. Our work is advised by our immediate limitations, but it&rsquo;s visiting that fork in the road where 4K television did not actually made people happier. And watching Terry Davis work on TempleOS, that was performance to me, because there was no place in my reality to make any use of it.</p> <p><em>Drew: Do you hope to offer the world something like that?</em></p> <p><strong>Devine</strong>: We work on small systems that people emulate on their M1.</p> <p><em>Drew: For any readers who want to check out your work, or get involved themselves, where should I direct them?</em></p> <p><strong>Rekka</strong>: To <a href="https://100r.co">our wiki</a>, <a href="https://xxiivv.com">Dev&rsquo;s website</a>, or <a href="https://kokorobot.ca">mine</a>, or to <a href="https://git.sr.ht/~rabbits/">git.sr.ht</a>, where we host our projects.</p> <p><strong>Devine</strong>: We&rsquo;ve been meaning to migrate to the new <a href="https://srht.site">sourcehut pages</a>, that&rsquo;s what&rsquo;s next.</p> <p><em>Drew: Cool! Thanks for taking some time to chat with me. I&rsquo;m very proud to host you on SourceHut, I&rsquo;m a big fan myself.</em></p> <p><em>Drew: Is there anything you wish I had asked or that we had discussed today?</em></p> <p><strong>Devine</strong>: Are you familiar with permacomputing? It&rsquo;s a holistic approach to computing and sustainability inspired from permaculture.</p> <p><em>Drew: No, tell me more.</em></p> <p><strong>Devine</strong>: Well, one thing that we&rsquo;ve been thinking about is like&hellip; Fahrenheit 451 is a book about the world ending, and a handful of people take it upon themselves to preserve books they think have meaning. We often see folks echoing that computing causes more problems than it solves, and that what was once a tool of emancipation has been warped into a tool of control.</p> <p><strong>Devine</strong>: Are computers something we&rsquo;d like to preserve going forward? How much is worth keeping? And so forth. This is what people consider when thinking about permacomputing. I don&rsquo;t know the answer but it&rsquo;s something interesting to explore. There isn&rsquo;t a critical mass of folks thinking about these ideas right now, but we&rsquo;re seeing more and more folks joining in the discussion.</p> <p>→ <em><a href="http://viznut.fi/texts-en/permacomputing.html">You can read more about permacomputing here</a>, and <a href="https://wiki.xxiivv.com/site/permacomputing.html">here</a>.</em></p> <p><em>Drew: I would like to see more thoughts on these lines, too. Hopefully we can signal boost that together and get some more brains involved.</em></p> <p><em>Drew: Speaking of which: let&rsquo;s open the floor to the rest of the channel?</em></p> <hr> <p>Following the interview, we opened the IRC channel back up to general discussion for a while. Here are a few choice quotes from the ensuing chat:</p> <blockquote> <p><strong>alderwick</strong>: One thing I specifically wanted to say about 100r and SourceHut is that I wouldn&rsquo;t have been able to contribute to Uxn if the repo was on GitHub. Like ddevault, I&rsquo;m on old hardware. My laptop won&rsquo;t load more than a few GitHub pages without crashing, but SourceHut is never a problem.</p> <p><strong>Devine</strong>: And without alderwick there would be no Uxn, I&rsquo;m endlessly thankful that it made our meeting possible.</p> <p><strong>sigrid</strong>: Echoing alderwick here. GitHub doesn&rsquo;t work on Plan 9 in Mothra. SourceHut does with no issues.</p> </blockquote> <blockquote> <p><strong>nihilazo</strong>: I like permacomputing as an idea but I struggle with it in a way because I&rsquo;m required to use cloud services and such. I had to start using a more powerful laptop just to run MS Teams. Is there some way to reconcile trying to do permacomputing-y stuff with also working within a world that (currently) requires I use garbage?</p> <p><strong>Devine</strong>: There is no way to reconcile using MS Teams and permacomputing.</p> <p><strong>AWildThorp</strong> (later): What are your thoughts on cloud services with respect to permacomputing? I have mixed feelings about them in general. I kind of view them as buses vs cars, but on the other hand they can enable wastefulness</p> <p><strong>nihilazo</strong>: I understand that you can&rsquo;t reconcile the two is there any way to contribute to permacomputing while still being trapped in systems antithetical to it?</p> <p><strong>Devine</strong>: Cloud services abstracts the waste from its users, I think until there&rsquo;s more transparency they are antithetical to permacomputing, otherwise they could be an efficient tool to create some sort of permeance of information.</p> <p><strong>eletrotupi</strong>: nihilazo: I think you can and should contribute to permacomputing regardless of being trapped. Unless you are deliberating picking up antithetical services.</p> <p><em>Devine agrees with eletrotupi</em></p> <p><strong>Drew</strong>: I think that most people aren&rsquo;t trapped even if they feel so, too. You usually have a choice. For instance, you could seek out a different employer, or save up and start your own business. Positive steps in the right direction are almost always possible.</p> <p><strong>nihilazo</strong>: I am trapped by having to use Teams for college work, and I can&rsquo;t really just switch colleges, given that they are the only college in the area.</p> <p><strong>Drew</strong>: You could start grassroots student organizations which try to tackle these issues. Throwing up your hands and saying it&rsquo;s out of your control is not the best option. It takes people taking deliberate action to make changes in our society.</p> <p><strong>nihilazo</strong>: I agree on that point, I guess.</p> </blockquote> <blockquote> <p><strong>Anonymous</strong>: Was sailing a transformational experience led to permacomputing as a goal? And if so - can the lifestyle change required to avoid &ldquo;MS Teams&rdquo; be achieved without such a strong transformational experience?</p> <p><strong>Devine</strong>: We had to be put in an extreme situation to make that drastic a change. As an example, we were making iOS development when we cast off, thinking that we could do it along the way. Now it seems to naive to believe that modern technology can even survive being 15 nautical miles from the coast without it totally breaking down. But, we don&rsquo;t think people have to be sailing to explore that space.</p> <p><strong>Rekka</strong>: Working from an older computer or from a shitty off-grid connection can help ;)</p> </blockquote> <blockquote> <p><strong>nihilazo</strong>: I&rsquo;ve been very conscious of the potential power consumption of my computer use and trying to cut down but I am finding it difficult. I&rsquo;m an internet addict, I guess. Especially things like video games, which are almost the very definition of pointless energy consumption.</p> <p><strong>Rekka</strong>: It&rsquo;s difficult without actual constraints. If you are limited to the power in your batteries, say. You know your limits and it&rsquo;s easy to limit usage.</p> <p><strong>kfx</strong>: I think it&rsquo;s possible to separate those worlds. I use all kinds of unfortunate technology at work, and I don&rsquo;t let it intrude on what I do for myself. Keeping those dividing lines sharp makes it easier to walk away from the gross stuff when the opportunity presents itself. Teams in fact was busily crashing my work computer about twenty minutes ago, but I kept reading this IRC discussion on my personal machine.</p> <p><strong>AWildThorp</strong>: On a similar note, if I go above my data limit on my smart phone, I have no bandwidth issues browsing the <a href="https://gemini.circumlunar.space/">gemini space</a>.</p> </blockquote> <blockquote> <p><strong>HamAdams</strong>: I&rsquo;m really glad you all did this interview. I think this is putty some words to some general feelings I&rsquo;ve been having recently regarding using technology more consciously.</p> <p><strong>Devine</strong>: Glad to hear :) The ComputingWithinLimit crew released a bunch of papers last year about this way of thinking about computers. The <a href="https://computingwithinlimits.org/2021/">LIMITS2021</a> papers are excellent; I recommend having a look. They will put even more words to these thoughts.</p> </blockquote> <p>Big thanks to the Rabbits for joining us for this interview! Please check out their cool projects. <a href="https://git.sr.ht/~rabbits/orca">Orca</a> is my personal favorite.</p> Announcing chat.sr.ht: a persistent IRC session for sourcehut users https://sourcehut.org/blog/2021-11-29-announcing-the-chat.sr.ht-public-beta/ Mon, 29 Nov 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-11-29-announcing-the-chat.sr.ht-public-beta/ <p>About one month ago, we began a private beta for <a href="https://chat.sr.ht">chat.sr.ht</a>, the next flagship sourcehut product. Starting today, this service is now available to all paid sourcehut users.</p> <p>chat.sr.ht is a hosted IRC bouncer service, which maintains a persistent IRC connection for you and extends IRC with useful features like offline messaging, log persistence, and various other improvements. In addition to accepting connections from any third-party IRC client, chat.sr.ht offers a ready-to-use web client.</p> <p><img src="https://l.sr.ht/iqm-.png" alt="A screenshot of chat.sr.ht&rsquo;s web chat feature, showing the #sr.ht chatroom"></p> <p>Like the rest of the SourceHut services, chat.sr.ht is powered by free software. The bouncer is based on <a href="https://soju.im">soju</a> and the web chat is based on <a href="https://sr.ht/~emersion/gamja/">gamja</a>. There are many other soju deployments in the wild — chat.sr.ht is just the newest. gamja is a standalone web client: it doesn&rsquo;t depend on specific server software and several independent networks provide it to their users today.</p> <p>The IRC networks you use with chat.sr.ht are independent entities, governed by their own stewards and unaffiliated with SourceHut. Thanks to the standard, open protocols that IRC is built on, chat.sr.ht users are able to participate in the established community of IRC networks like <a href="https://libera.chat">Libera Chat</a>.</p> <p>Our main goal is to make IRC easier to use for free software projects. For example, the bouncer exposes a special protocol extension to automatically connect to all of your IRC networks, which helps skip the tedious process of configuring every network you use. The web client can also be configured to open irc:// links around the web, so that getting involved in a project&rsquo;s discussion can be as easy as clicking a link in the project&rsquo;s README.</p> <p>Our work is not limited to chat.sr.ht itself — we want to improve the IRC ecosystem as a whole. We are involved in upstream <a href="https://ircv3.net/">IRCv3</a> development: we participate in the standardization process by providing implementations and feedback for work-in-progress specifications (for instance <a href="https://ircv3.net/specs/extensions/chathistory">chathistory</a>), and we&rsquo;re also pushing new specifications (for instance <a href="https://ircv3.net/specs/extensions/extended-monitor">extended-monitor</a>). Additionally, we&rsquo;ve been contributing to <a href="https://modern.ircdocs.horse/">modern-irc</a>, the de-facto IRC reference document. We want chat.sr.ht to be a platform for improving the IRC community.</p> <p>Moving forward, we plan to continue collaborating with the IRC community and improving the IRC standards. Our first priority is to develop the <a href="https://ircv3.net/specs/extensions/account-registration">account-registration</a> implementation in upstream ircds, which will bring a first-class network registration protocol to IRC. We&rsquo;re also hoping to add anonymous access to chat.sr.ht, so non-paying users or users without a sourcehut account can participate in your project&rsquo;s chat room.</p> <p>In the meantime, please give it a shot! Head over to <a href="https://chat.sr.ht">chat.sr.ht</a> to take it a spin.</p> SourceHut's third year https://sourcehut.org/blog/2021-11-15-sourcehuts-third-year/ Mon, 15 Nov 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-11-15-sourcehuts-third-year/ <p>Three years ago today, <a href="https://drewdevault.com/2018/11/15/sr.ht-general-availability.html">I announced</a> that SourceHut would be making its alpha open to the general public after two years of development in private. Since then, in addition to moving across the Atlantic ocean, I have overseen the development of a service, and a business, which has grown to exceed all of my expectations. Today, SourceHut is home to 25,000 users, 5,000 projects, 42,000 git repos and 5,000 Mercurial repos. 153,000 emails have made their way to the 3,000 mailing lists hosted here, and 26,000 tickets have been filed across 5,000 bug trackers. Our CI system has completed 625,000 builds totalling 2½ years of continuous build time.</p> <p>And so, despite its persistent &ldquo;alpha&rdquo; status, SourceHut has been a comfortable home to thousands of projects productively going about the business of building free software. I couldn&rsquo;t be more proud of our work, or more thankful for the trust and support this community has offered us.</p> <p>In return, what have we offered the FOSS community? Earlier this week, <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CCFL3CMT80O75.KMUQOE9PQ90B%40taiga%3E">I asked the sr.ht-discuss mailing list</a> to share some of their favorite projects on SourceHut. The favorites include a <a href="https://sr.ht/~gardenapple/mitch/">mobile client for itch.io</a>, a <a href="https://sr.ht/~tenacity/tenacity/">multi-track audio editor</a> reclaimed from the hostile takeover of Audacity, a <a href="https://sr.ht/~mil/Mepo/">hacker-first OpenStreetMap viewer</a>, a <a href="https://sr.ht/~edwardloveall/Scribe/">user-first Medium frontend</a>, and <a href="https://sr.ht/projects/~sourceware/">official mirrors of SourceWare projects</a> like GCC and glibc, all of which are new to SourceHut this year. I also recently discovered that the French government&rsquo;s <a href="https://code.gouv.fr/#/about">new site for discovering French FOSS projects</a> uses SourceHut as well. Check out the thread for more, or reply to add some of your own favorites!</p> <p>SourceHut staff have also been hard at work contributing directly to free software again this year. As part of our <a href="https://sourcehut.org/consultancy/">free software consultancy</a>, we have taken on projects like expanding <a href="https://www.khronos.org/OpenXR/">OpenXR</a> support on Linux, contributing to projects like the Linux kernel, Monado, Mesa, Xwayland, and more. We&rsquo;re also responsible for <a href="https://github.com/Plagman/gamescope">the free software Wayland technology</a> at the heart of Valve&rsquo;s <a href="https://www.steamdeck.com/en/">Steam Deck</a>. We are also the release managers for Wayland and Weston, and maintainers for parts of the <a href="https://www.freedesktop.org/wiki/">freedesktop</a> and <a href="https://alpinelinux.org/">Alpine Linux</a> infrastructure, and we became a <a href="https://wiki.osmfoundation.org/wiki/Corporate_Members#Bronze_Corporate_Members">Bronze supporter</a> of OpenStreetMap this year.</p> <p>Many new free software projects have also been developed and organized by our staff, including an <a href="https://sr.ht/~emersion/soju">IRC bouncer</a> and <a href="https://sr.ht/~emersion/gamja">webchat</a>, a <a href="https://godocs.io">documentation site for Go</a>, a new <a href="https://sr.ht/~sircmpwn/visurf">web browser</a> based on NetSurf, and a project to <a href="https://drewdevault.com/2021/03/19/A-new-systems-language.html">develop a new programming language</a>. Our <a href="https://forgeperf.org/">forgeperf</a> initiative has also turned our industry-leading focus on performance and accessibility into tangible improvements in <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/222685">GitLab</a> and <a href="https://codeberg.org/Codeberg/Community/issues/176">Codeberg</a>. We will also be hiring a third engineer in February who will help us expand this work even more. In keeping with our tradition of transparency, the <a href="https://man.sr.ht/staff/culture.md">onboarding documents</a> we prepared for them are available to the public.</p> <p>And what of the forge itself? Our main focus this year has been on implementing our <a href="https://sourcehut.org/blog/2020-06-10-how-graphql-will-shape-the-alpha/">GraphQL API</a>, which is now about halfway done. This is the main blocker for the SourceHut beta, and we have by now solved most of the unknowns and are working our way through the rote work of building out the remainder of the services. I&rsquo;ll predict, for the third time, that we&rsquo;ll complete the alpha and start the beta next year.</p> <p>We&rsquo;re comfortable taking our time to do this right, especially given that we&rsquo;re quite able to provide a great deal of value to the FOSS community even during the alpha. Our definition of &ldquo;alpha&rdquo; has a specific meaning which differs from many other projects, specifically boiling down to meeting four important criteria:</p> <ul> <li>Support for user groups/organizations</li> <li>The development of a high-quality API which we can support indefinitely</li> <li>Complete data autonomy, including import and export and account deletion</li> <li>Comprehensive documentation for both hosted and self-hosting users</li> </ul> <p>When we meet these criteria, we will have reached the necessary level of quality to ship a product we can be confident in for the long-term. However, we have <em>already</em> reached many important milestones which are uncharacteristic of many alpha-quality products. We&rsquo;re committed to the longevity of user data, and we have many levels of redundant backups and monitoring. Our services are also extremely reliable, sporting better uptime than any of our competitors, including big fish like GitHub. Thousands of projects are already enjoying productive use of our services, and our goal is to provide them with a best-in-class product which far exceeds their expectations and industry norms.</p> <p>In addition to this work in advancing the GraphQL APIs towards our ultimate ambitions of completing the alpha, we have also taken some time to develop additional products and foster a culture of shared community ownership over our services. We shipped <a href="https://srht.site">pages.sr.ht</a> this year, and we&rsquo;re expecting to ship our hosted IRC services, <a href="https://sourcehut.org/blog/2021-10-15-whats-cooking-october-2021/#chatsrht">chat.sr.ht</a>, very soon. We&rsquo;ve also continued to enjoy a great relationship with the Mercurial community, who are directly responsible for the maintenance of hg.sr.ht, in addition to the many volunteers representing <a href="https://man.sr.ht/builds.sr.ht/compatibility.md">their operating systems</a> on builds.sr.ht. Members of our community are also working independently to develop names.sr.ht, which will eventually become a domain name registrar which uses git to store zone files and supports cool ideas like <a href="https://www.opennic.org">OpenNIC</a>. We&rsquo;re looking forward to involving the community even more in the coming years, as this is a key advantage of SourceHut&rsquo;s FOSS design that many of our competitors lack — and works to the mutual benefit of SourceHut and the communities which rely on us. If you have a cool idea for SourceHut and you&rsquo;re willing to write the code, we&rsquo;re willing to provide you with support and resources to deploy it to.</p> <p>With that, another year goes by, and the year ahead is full of work to do. I hope you&rsquo;ll join our public Mumble meeting tomorrow to look back on our accomplishments, and look forward to the future. We&rsquo;re meeting in the usual place, voice.mnus.de in the SourceHut room, at 10:00 UTC tomorrow, November 16th. Thank you for using SourceHut, and I hope we continue to serve you into the future.</p> <h2 id="whats-cooking-on-sourcehut">What&rsquo;s cooking on SourceHut?</h2> <p>Let&rsquo;s quickly address the usual &ldquo;what&rsquo;s cooking&rdquo; items before parting ways.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Write support for the todo.sr.ht GraphQL API was my main focus this month, but it has turned out to be pretty complicated. todo.sr.ht is one of the most complex sourcehut services — submitting a ticket requires parsing user mentions, fetching subscribers, creating ticket and event rows, fetching or referencing new participants, sending email notifications, and more. I hope to complete this next month.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Legacy Fedora images are being deprecated and removed next week. You will receive an email if this affects you. Thanks to Haowen Liu for taking over maintenance of the Fedora images, and to Timothée Floure for all of their hard work up to now.</p> <p>apt-key has been deprecated in Debian upstream, and builds.sr.ht has been updated according to upstream recommendations. This is not expected to impact users.</p> <p>We have stopped allocating a PTY for build logs. This may cause your build results to look less colorful, but should cause few problems otherwise.</p> <p>Additionally:</p> <ul> <li>openbsd/7.0 is now available</li> <li>ubuntu/jammy is now available</li> </ul> <h2 id="pagessrht">pages.sr.ht</h2> <p>pages.sr.ht now supports partially updating only a subdirectory of your sites, which makes it easier to do things like manage different subdirectories for different projects without having all of them necessarily being aware of the content of the entire site.</p> What's cooking on SourceHut? October 2021 https://sourcehut.org/blog/2021-10-15-whats-cooking-october-2021/ Fri, 15 Oct 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-10-15-whats-cooking-october-2021/ <p>Welcome back for another month&rsquo;s status update! As of today, our community numbers at 25,074 — the first time we&rsquo;ve had over 25,000 users — after another 522 users joined our ranks. Please show them the courtesey and patience you&rsquo;ve always done as they learn the ropes, and welcome these new users to our community with open arms.</p> <p>This month’s Mumble meeting will take place on Monday, October 18th, at 10:00 UTC. We’ll be on voice.mnus.de, port 64738, in the sourcehut room. See you there!</p> <h2 id="chatsrht">chat.sr.ht</h2> <p>The first item on today&rsquo;s agenda is a tiny preview of a new flagship SourceHut product: chat.sr.ht. More details will come in a dedicated announcement in a couple of weeks, but in short, chat.sr.ht is a hosted IRC bouncer based on <a href="https://sr.ht/~emersion/soju/">soju</a> which will offer all paying SourceHut users a persistent IRC session, and a webchat based on <a href="https://sr.ht/~emersion/gamja/">gamja</a>, which will also provide a non-persistent session for non-paying and anonymous users.</p> <p><img src="https://l.sr.ht/iqm-.png" alt="A screenshot of chat.sr.ht&rsquo;s web chat feature, showing the #sr.ht chatroom"></p> <p>Short answers:</p> <ul> <li>We aren&rsquo;t running an IRC network ourselves. We&rsquo;re going to encourage users to use <a href="https://libera.chat">Libera Chat</a> for their projects, though you can configure it to use any network (or networks) you want.</li> <li>You can connect to the bouncer directly using your own IRC client, or use the webchat at chat.sr.ht.</li> <li>irc:// links in your README and throughout SourceHut will be rigged up to auto-join your channel in our webchat when clicked.</li> </ul> <p>The service is up and running, but currently set up as a private beta so that we can get everything tested and validated on a small scale. If you want to try the private beta, reach out to emersion on libera.chat.</p> <h2 id="graphql">GraphQL</h2> <p>This month, I implemented both read &amp; write support for paste.sr.ht&rsquo;s new GraphQL API, which you can try out here:</p> <ul> <li><a href="https://paste.sr.ht/graphql">paste.sr.ht GraphQL playground</a></li> <li><a href="https://git.sr.ht/~sircmpwn/paste.sr.ht/tree/master/item/api/graph/schema.graphqls">paste.sr.ht GraphQL schema</a></li> </ul> <p>No native webhooks, but that&rsquo;ll come later. I have also started working on write support for todo.sr.ht, which is actually quite complex and challenging — todo.sr.ht is one of the most complex services on SourceHut. I&rsquo;m hoping to finish that over the course of the next month, and hopefully I can tick off another check-mark on the list as well.</p> <dl> <dt>meta.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>git.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>hg.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>todo.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>builds.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>lists.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>hub.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>paste.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>pages.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> </dl> <h2 id="todosrht">todo.sr.ht</h2> <p>In addition to the ongoing GraphQL work, todo.sr.ht has received some major updates with how it handles permissions and access lists. If you were affected by the change, you should have received an email explaining how to address it for your trackers. In short, trackers now have a &ldquo;visibility&rdquo; parameter which behaves the same as for git repos (public, private, or unlisted), and the default permissions have been consolodated into one field which applies to any users who do not have a more specific ACL entry. A similar change will soon come for lists.sr.ht.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>Eli Schwartz has implemented a novel system based on git notes for attaching cryptographic signatures to git tags. He&rsquo;ll be writing a guest post for this blog sometime soon which goes over this feature in detail.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Image updates:</p> <ul> <li>freebsd/11.x has been removed following its upstream deprecation.</li> <li>GNU Guix is now available.</li> </ul> What's cooking on SourceHut? September 2021 https://sourcehut.org/blog/2021-09-15-whats-cooking-september-2021/ Wed, 15 Sep 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-09-15-whats-cooking-september-2021/ <p>Another month passes us by, recording further progress on the road to the sr.ht beta. Joining us on this journey are another 448 new souls, bringing our total number to 24,552. As always, I&rsquo;m depending on you to show them kindness and patience as they learn how to use SourceHut.</p> <p>This month’s Mumble meeting will take place on the tomorrow, September 16th, at 10:00 UTC. We’ll be on voice.mnus.de, port 64738, in the sourcehut room.</p> <h2 id="general-news">General news</h2> <p>SourceHut put out a <a href="https://sourcehut.org/blog/2021-08-23-work-at-sourcehut/">job posting</a> (now closed) a few weeks ago, and we have received many excellent applications. We are planning on making an offer to one of these candidates, and the details will be announced in the next status update. We have also spoken with <a href="https://nlnet.nl">NLnet</a>, who may be interested in funding some additional contributors to work on SourceHut. Exciting stuff!</p> <p>Also, as of this month, SourceHut is a bronze sponsor of the <a href="https://wiki.osmfoundation.org/wiki/Corporate_Members#Bronze_Corporate_Members">OpenStreetMap Foundation</a>. We are proud to support a critical resource for free software and open data.</p> <h2 id="graphql">GraphQL</h2> <p>Following the deployment of the first implementation of <a href="https://sourcehut.org/blog/2021-08-25-graphql-native-webhooks/">GraphQL-native webhooks</a> for meta.sr.ht, our GraphQL completion chart has a new column:</p> <dl> <dt>meta.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-success">✓</strong> webhooks</dd> <dt>git.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>hg.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>todo.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>builds.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>lists.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>hub.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>paste.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write <strong class="text-danger">✗</strong> webhooks</dd> <dt>pages.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write <strong class="text-danger">✗</strong> webhooks</dd> </dl> <p>Additionally, we deployed write support for lists.sr.ht this week. You can find the updated schema here: <a href="https://git.sr.ht/~sircmpwn/lists.sr.ht/tree/master/item/api/graph/schema.graphqls">lists.sr.ht schema.graphqls</a>.</p> <p>I have written up a draft for the paste.sr.ht GraphQL API design here: <a href="https://git.sr.ht/~sircmpwn/paste.sr.ht/tree/api/item/api/graph/schema.graphqls">paste.sr.ht schema.graphqls</a>, which I intend to flesh out with an implemenation in the coming weeks (and also add GQL webhooks — it&rsquo;s simple enough that we should be able to ship a complete GQL implementation in the first iteration). Ludovic and co. have also been hard at work on the first round of GraphQL support for hg.sr.ht, which is likely to ship in the foreseeable future. Following these, I would like to either implement a read-only hub.sr.ht GQL API, or add write support to todo.sr.ht, either of which is a considerable effort in their own right.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Thanks to Ivan Habunek&rsquo;s work, you can now specify the sort order of results on todo.sr.ht searches. Thanks Ivan!</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Image updates:</p> <ul> <li>Rocky Linux is now available (thanks Haowen Liu!)</li> <li>debian/bookworm is now available, and stretch has been removed</li> <li>ubuntu/xenial has been removed</li> </ul> <p>Tanguy Fardet also sent in their first patch this month, adding a &ldquo;go to top&rdquo; button on the build logs page. Thanks Tanguy!</p> Introducing a GraphQL-native approach to webhooks https://sourcehut.org/blog/2021-08-25-graphql-native-webhooks/ Wed, 25 Aug 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-08-25-graphql-native-webhooks/ <p>Today, we are shipping a new system for webhooks for use with our suite of <a href="https://sourcehut.org/blog/2020-06-10-how-graphql-will-shape-the-alpha/">GraphQL APIs</a>, which are <a href="https://sourcehut.org/blog/2020-09-25-api-2-updates/">under development</a> as part of our larger <a href="https://sourcehut.org/alpha-details/">beta plans</a>. We&rsquo;re not the first to use this design for webhooks, but it is somewhat uncommon, so I&rsquo;ll take this opportunity to explain it to those who may be unfamiliar with it.</p> <p>Let&rsquo;s first establish, for contrast, how traditional webhooks work. Here&rsquo;s an example of a webhook payload from GitHub:</p> <details> <summary>Click to expand (large)</summary> <pre> { "action": "opened", "number": 2, "pull_request": { "url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2", "id": 279147437, "node_id": "MDExOlB1bGxSZXF1ZXN0Mjc5MTQ3NDM3", "html_url": "https://github.com/Codertocat/Hello-World/pull/2", "diff_url": "https://github.com/Codertocat/Hello-World/pull/2.diff", "patch_url": "https://github.com/Codertocat/Hello-World/pull/2.patch", "issue_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/2", "number": 2, "state": "open", "locked": false, "title": "Update the README with new information.", "user": { "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false }, "body": "This is a pretty simple change that we need to pull into master.", "created_at": "2019-05-15T15:20:33Z", "updated_at": "2019-05-15T15:20:33Z", "closed_at": null, "merged_at": null, "merge_commit_sha": null, "assignee": null, "assignees": [], "requested_reviewers": [], "requested_teams": [], "labels": [], "milestone": null, "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/commits", "review_comments_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/comments", "review_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/comments{/number}", "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/2/comments", "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/ec26c3e57ca3a959ca5aad62de7213c562f8c821", "head": { "label": "Codertocat:changes", "ref": "changes", "sha": "ec26c3e57ca3a959ca5aad62de7213c562f8c821", "user": { "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false }, "repo": { "id": 186853002, "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", "name": "Hello-World", "full_name": "Codertocat/Hello-World", "private": false, "owner": { "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false }, "html_url": "https://github.com/Codertocat/Hello-World", "description": null, "fork": false, "url": "https://api.github.com/repos/Codertocat/Hello-World", "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", "created_at": "2019-05-15T15:19:25Z", "updated_at": "2019-05-15T15:19:27Z", "pushed_at": "2019-05-15T15:20:32Z", "git_url": "git://github.com/Codertocat/Hello-World.git", "ssh_url": "[email protected]:Codertocat/Hello-World.git", "clone_url": "https://github.com/Codertocat/Hello-World.git", "svn_url": "https://github.com/Codertocat/Hello-World", "homepage": null, "size": 0, "stargazers_count": 0, "watchers_count": 0, "language": null, "has_issues": true, "has_projects": true, "has_downloads": true, "has_wiki": true, "has_pages": true, "forks_count": 0, "mirror_url": null, "archived": false, "disabled": false, "open_issues_count": 2, "license": null, "forks": 0, "open_issues": 2, "watchers": 0, "default_branch": "master", "allow_squash_merge": true, "allow_merge_commit": true, "allow_rebase_merge": true, "delete_branch_on_merge": false } }, "base": { "label": "Codertocat:master", "ref": "master", "sha": "f95f852bd8fca8fcc58a9a2d6c842781e32a215e", "user": { "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false }, "repo": { "id": 186853002, "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", "name": "Hello-World", "full_name": "Codertocat/Hello-World", "private": false, "owner": { "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false }, "html_url": "https://github.com/Codertocat/Hello-World", "description": null, "fork": false, "url": "https://api.github.com/repos/Codertocat/Hello-World", "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", "created_at": "2019-05-15T15:19:25Z", "updated_at": "2019-05-15T15:19:27Z", "pushed_at": "2019-05-15T15:20:32Z", "git_url": "git://github.com/Codertocat/Hello-World.git", "ssh_url": "[email protected]:Codertocat/Hello-World.git", "clone_url": "https://github.com/Codertocat/Hello-World.git", "svn_url": "https://github.com/Codertocat/Hello-World", "homepage": null, "size": 0, "stargazers_count": 0, "watchers_count": 0, "language": null, "has_issues": true, "has_projects": true, "has_downloads": true, "has_wiki": true, "has_pages": true, "forks_count": 0, "mirror_url": null, "archived": false, "disabled": false, "open_issues_count": 2, "license": null, "forks": 0, "open_issues": 2, "watchers": 0, "default_branch": "master", "allow_squash_merge": true, "allow_merge_commit": true, "allow_rebase_merge": true, "delete_branch_on_merge": false } }, "_links": { "self": { "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2" }, "html": { "href": "https://github.com/Codertocat/Hello-World/pull/2" }, "issue": { "href": "https://api.github.com/repos/Codertocat/Hello-World/issues/2" }, "comments": { "href": "https://api.github.com/repos/Codertocat/Hello-World/issues/2/comments" }, "review_comments": { "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/comments" }, "review_comment": { "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/comments{/number}" }, "commits": { "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/commits" }, "statuses": { "href": "https://api.github.com/repos/Codertocat/Hello-World/statuses/ec26c3e57ca3a959ca5aad62de7213c562f8c821" } }, "author_association": "OWNER", "draft": false, "merged": false, "mergeable": null, "rebaseable": null, "mergeable_state": "unknown", "merged_by": null, "comments": 0, "review_comments": 0, "maintainer_can_modify": false, "commits": 1, "additions": 1, "deletions": 1, "changed_files": 1 }, "repository": { "id": 186853002, "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", "name": "Hello-World", "full_name": "Codertocat/Hello-World", "private": false, "owner": { "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false }, "html_url": "https://github.com/Codertocat/Hello-World", "description": null, "fork": false, "url": "https://api.github.com/repos/Codertocat/Hello-World", "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", "created_at": "2019-05-15T15:19:25Z", "updated_at": "2019-05-15T15:19:27Z", "pushed_at": "2019-05-15T15:20:32Z", "git_url": "git://github.com/Codertocat/Hello-World.git", "ssh_url": "[email protected]:Codertocat/Hello-World.git", "clone_url": "https://github.com/Codertocat/Hello-World.git", "svn_url": "https://github.com/Codertocat/Hello-World", "homepage": null, "size": 0, "stargazers_count": 0, "watchers_count": 0, "language": null, "has_issues": true, "has_projects": true, "has_downloads": true, "has_wiki": true, "has_pages": true, "forks_count": 0, "mirror_url": null, "archived": false, "disabled": false, "open_issues_count": 2, "license": null, "forks": 0, "open_issues": 2, "watchers": 0, "default_branch": "master" }, "sender": { "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false } } </pre> </details> <p>SourceHut offers a similar approach with our legacy API. The problem here is information overload. This payload contains a <em>lot</em> of information, almost none of which you actually need, and may omit information you <em>do</em> want. One of our services, dispatch.sr.ht, uses this particular GitHub payload to configure build submissions for projects who want to use GitHub for git hosting and builds.sr.ht for CI. When we receive this webhook, we need to make several follow-up API requests to collect the necessary information for build submission.</p> <p>With the new GraphQL design, the user submits not only the URL and events they want to receive, but also a GraphQL query which will be executed to customize the request payload that will be sent to them. In this custom payload, you are able to collect not only information about the event which occured, but also any other information you would find in a typical GraphQL request. So, to accomplish similar functionality for submitting a build manifest on a git push, we can configure a webhook with the following query:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-graphql" data-lang="graphql"><span class="line"><span class="cl"><span class="kd">query</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c"># Collect details about the event which triggered the webhook</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nc">webhook</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">uuid</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">date</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">profile</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="py">username</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">...</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">GitPushEvent</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">refs</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">old</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="py">sha</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">new</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">sha</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">author</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="py">name</span><span class="p">,</span><span class="w"> </span><span class="py">email</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">message</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c"># Collect build manifests</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">repository</span><span class="p">(</span><span class="py">id</span><span class="p">:</span><span class="w"> </span><span class="nc">1234</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c"># Case 1: several manifests under .builds/*.yml</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">multiple</span><span class="p">:</span><span class="w"> </span><span class="nc">path</span><span class="p">(</span><span class="py">path</span><span class="p">:</span><span class="s">&#34;.builds&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nc">object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">...</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">Tree</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">entries</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">results</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">name</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="kd">...</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">TextBlob</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="py">text</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c"># Case 2: one manifest at .build.yml</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="py">single</span><span class="p">:</span><span class="w"> </span><span class="nc">path</span><span class="p">(</span><span class="py">path</span><span class="p">:</span><span class="s">&#34;.build.yml&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nc">object</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">...</span><span class="w"> </span><span class="kd">on</span><span class="w"> </span><span class="py">TextBlob</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="py">text</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w"> </span></span></span></code></pre></div><p>This is executed on the server <em>before</em> sending the webhook to our URL, and collects all of the information we need, and none of the information we don&rsquo;t. We are then able to act on this webhook without any additional API requests. The payload we ultimately receive looks something like this:</p> <pre tabindex="0"><code>{ &#34;data&#34;: { &#34;webhook&#34;: { &#34;uuid&#34;: &#34;date&#34;: &#34;profile&#34;: { &#34;username&#34;: &#34;sircmpwn&#34; }, &#34;refs&#34;: [ &#34;old&#34;: { &#34;sha&#34;: &#34;81e98daa8341b1b5319645fecc81c7ba051c04d6&#34; }, &#34;new&#34;: { &#34;sha&#34;: &#34;64aff2197e08a687fca5779057bd0ac3341fea8f&#34;, &#34;author&#34;: { &#34;name&#34;: &#34;Drew DeVault&#34;, &#34;email&#34;: &#34;[email protected]&#34; }, &#34;message&#34;: &#34;This is a commit message&#34; } ] }, &#34;repository&#34;: { &#34;multiple&#34;: { &#34;object&#34;: { &#34;entries&#34;: { &#34;results&#34;: [ { &#34;name&#34;: &#34;alpine.yml&#34;, &#34;object&#34;: { &#34;text&#34;: &#34;image: alpine/3.14\nrepositories: ...&#34; } }, { &#34;name&#34;: &#34;archlinux.yml&#34;, &#34;object&#34;: { &#34;text&#34;: &#34;image: archlinux\nrepositories: ...&#34; } }, { &#34;name&#34;: &#34;debian.yml&#34;, &#34;object&#34;: { &#34;text&#34;: &#34;image: debian/sid\nrepositories: ...&#34; } } ] } } }, &#34;single&#34;: null } } } </code></pre><p>We only have the information we need, and nothing we don&rsquo;t, and we can fetch arbitrary information from the entire system to build our webhook payload without making any further API requests. Nice!</p> <p>The GraphQL schema has been expanded with tools for managing webhooks, such as browsing past deliveries. There is also a resolver which generates a sample webhook event, which you can use for testing your GraphQL query. We&rsquo;ll be rolling this out for meta.sr.ht&rsquo;s API first, and expanding it to support more services in the future. You can learn more in our documentation:</p> <ul> <li><a href="https://man.sr.ht/graphql.md">SourceHut GraphQL docs</a></li> <li><a href="https://git.sr.ht/~sircmpwn/meta.sr.ht/tree/master/item/api/graph/schema.graphqls">meta.sr.ht GraphQL Schema</a></li> </ul> <p>Swing by <a href="https://web.libera.chat/gamja/?channels=%23sr.ht">our IRC channel</a> (<a href="irc://irc.libera.chat/#sr.ht">irc://</a>) or fire off an email to <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a> if you have questions or feedback!</p> SourceHut is hiring FOSS software engineers https://sourcehut.org/blog/2021-08-23-work-at-sourcehut/ Mon, 23 Aug 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-08-23-work-at-sourcehut/ <p><strong>This opening is now closed</strong>. Please check back again later for future openings. Thanks!</p> <p>SourceHut is hiring paid software engineers to work exclusively on free and open source software. This is a full-time remote position. Our mission is simple:</p> <blockquote> <p>We are here to make free software better. We will be honest, transparent, and empathetic. We care for our users, and we will not exploit them, and we hope that they will reward our care and diligence with success.</p> </blockquote> <p>SourceHut is a ragtag group of hacker&rsquo;s hackers, but note that we will have to be decidedly un-hackish when explaining things in business terms. Bear with us.</p> <p>SourceHut is an early-stage bootstrapped company, which means that we are a young company that hasn&rsquo;t taken any outside investments. This gives us greater autonomy and allows us to maintain our principles and ethics without deference to financial concerns. However, we have much less capital to work with, and stringent margins, which may affect you.</p> <p>We have two main revenue streams: the forge product, and FOSS consulting. The forge product provides a reliable, but small, supply of income. We use this to pay out base salaries which are, frankly, well below market rates. We each earn a standard rate of $2,500 USD/mo, which may be supplemented with consulting work. Under the base arrangement, you are free to decide your own working schedule and choose any FOSS projects to work on.</p> <p>Per the missive of &ldquo;making free software better&rdquo;, those projects can include projects which are not stewarded by SourceHut or directly relevant to our financial interests. We make regular contributions to a wide variety of projects in the FOSS ecosystem which have little to no direct relevance to our bottom line. We believe that by growing the FOSS ecosystem, we are making a larger market, and are making ourselves an essential part of it, which will play out in our favor (and in society&rsquo;s favor) over the long term. You can work on your personal projects at SourceHut, and we encourage you to take bold risks on ambitious projects.</p> <p>Our secondary income stream is through free software consulting, which provides us much more revenue than the forge, but less reliably. 100% of this work is free and open source software, written in the open. We don&rsquo;t sign NDAs or non-competes. We take on 2-5 contracts per year, each lasting anywhere from 3-12 months, and you may choose which consulting projects you wish to work on. We charge high-end consulting rates, take a modest margin, and pay the rest to you. Our margin provides more capital for things like hiring new employees, expanding the forge infrastructure, long-term business planning, or simply paying out bonuses at the end of an engagement.</p> <p>You have the level of autonomy and independence which best supports your needs. We have, at a minimum, bi-weekly open-ended 1-on-1 meetings, and a monthly all-hands meeting. Beyond this, the level of autonomy you enjoy is based on your need: our senior engineers get by with a vague missive of &ldquo;make FOSS better&rdquo; or &ldquo;can you help with this one thing if you have time&rdquo;, while more junior engineers may receive more structured work to provide better learning and experience.</p> <p>In short, at SourceHut, you work on free and open source software, on the projects you want, on the schedule you want, and with the independence of judgement that respects you as an experienced, knowsome engineer. You work with smart and supportive peers on meaningful projects for an ethical business and a principled team. However, you receive a meager base salary, which, when combined with optional consulting work, can raise your annual pay to market, but with an inconsistency which may impact your personal financial planning. This is an arrangement which cannot suit everyone, but if it suits you, we&rsquo;ll be pleased to have you along.</p> <p>If you are interested in working with us, please send a plain-text email summarizing your interest, with your resume attached as a PDF file, to <a href="mailto:~sircmpwn/[email protected]">~sircmpwn/[email protected]</a>.</p> What's cooking on Sourcehut? August 2021 https://sourcehut.org/blog/2021-08-15-whats-cooking-august-2021/ Sun, 15 Aug 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-08-15-whats-cooking-august-2021/ <p>Hello again! Today we&rsquo;re joined by 434 fresh faces, bringing us to a total of 24,104 users. As always, I&rsquo;m relying on you to give a warm welcome to our new colleagues and to exercise patience as they learn the ropes.</p> <p>This month&rsquo;s Mumble meeting will take place on the normal date tomorrow, August 16th, at 10:00 UTC. We’ll be on voice.mnus.de, port 64738, in the sourcehut room.</p> <p>After another month of development, how much closer are we to beta?</p> <h2 id="operations">Operations</h2> <p>sr.ht for Alpine 3.14 <a href="https://lists.sr.ht/~sircmpwn/sr.ht-admins/%3CCD9T5BZ8RR79.12IPQT8UKJZOC%40taiga%3E">is now available</a>. Thank you for bearing with us during our planned maintenance window. I&rsquo;ll ask for your patience again tomorrow, as we have a <a href="https://status.sr.ht/issues/2021-08-16-planned-outage/">second maintenance window scheduled</a> to finish our 3.14 rollout.</p> <h2 id="graphql">GraphQL</h2> <p>The current major milestone for the beta is the development and rollout of our GraphQL APIs, which form a more robust foundation for us to build upon.</p> <p>This month, we shipped a read-only version of the lists.sr.ht GraphQL API. You can check it out here:</p> <ul> <li><a href="https://lists.sr.ht/graphql">GraphQL Playground</a></li> <li><a href="https://man.sr.ht/lists.sr.ht/graphql.md">Manual</a></li> </ul> <p>The latest GQL rollout progress is now:</p> <dl> <dt>meta.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write</dd> <dt>git.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write</dd> <dt>hg.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>todo.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>builds.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write</dd> <dt>lists.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>hub.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>paste.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>pages.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write</dd> </dl> <p>I have been prototyping GraphQL-native webhooks, which is the only outstanding major design concern for the GraphQL rollout. I expect to roll these out for meta.sr.ht in the next month. I will also start turning another one of these <strong class="text-danger">✗</strong> into <strong class="text-success">✓</strong>, but I&rsquo;m not sure which yet.</p> <p>Ludovic Chabant has also prepared a prototype for a read-only hg.sr.ht GraphQL API, which I will find some time to review this month.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>The following image updates have been shipped:</p> <ul> <li>Ubuntu Impish and Hirsute are now available</li> <li>Ubuntu Groovy was removed following its upstream deprecation</li> </ul> <p>It is also expected that Rocky Linux will soon be available thanks to the efforts of Haowen Liu and Timothée Floure.</p> <h2 id="miscellaneous">Miscellaneous</h2> <p>Thanks are due to several community members for their contributions this month. Sol Fisher Romanoff did the long-stale job of auditing and unifying the naming conventions for resources like git repos or bug trackers across all services, along with some unrelated minor improvements. Thanks also to Nguyễn Gia Phong, LordNature, and Juan Picca for their various contributions.</p> The mythical 10× programmer is just a good leader https://sourcehut.org/blog/2021-07-17-the-10x-programmer-is-a-leader/ Sat, 17 Jul 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-07-17-the-10x-programmer-is-a-leader/ <p>There is some truth to the idea that some programmers are more productive than others. In practice, this is mainly a function of the breadth and depth of their experience, rather than an expression of innate talent. Under the right circumstances, the difference between two programmers can be significant, though a single programmer who is 10× more productive than the average is quite rare.</p> <p>There does exist, however, a means of substantially improving productivity without relying on superstars: good leadership.</p> <p>The difference between a one-person project which takes 5 years to complete, and a 10-person project which takes 2 years, is nine people. The ability for a maintainer to sell their project to potential contributors and inspire people to get involved is a major productivity hack. With 10 more years of experience, you may find yourself a 10× better programmer, but with 10 more <em>programmers</em>, you can get results today. This is especially true in FOSS, where attracting volunteers is often a key competency of successful projects.</p> <p>Organizing the work is the most important task in this role. You need to hold a vision of the project in your head, and an actionable plan for executing it. This need only have enough detail to ensure that (1) you know what needs to be done, and in what order, and (2) you have enough work to keep everyone busy.</p> <p>In my workflow, I aim to identify the most difficult problems first (those with the most unknowns), then have senior engineers address them upfront. This tends to create a lot of ancillary tasks which can be taken on by contributors at a broad range of skill levels, keeping a healthy pool of tasks ready for everyone who wants something to work on. It also makes the difficulty of the work trend towards zero, which helps a lot with planning, since you get a firmer and firmer picture of the remaining work over time. The goal is to quickly create a thin skeleton which can support work on the project&rsquo;s largest challenges, allowing senior engineers to focus on the core problems while others put meat on those bones, planning out junior- to mid-level problems as they become apparent.</p> <p>Working with the contributors on an individual basis is the next matter of concern. It&rsquo;s up to the leaders to understand the interests and capabilities of each contributor, and help line up impactful work which they will find rewarding. Furthermore, you need to help them lay down a path of experience in which they can grow to understand more of the project&rsquo;s scope, approach it with greater skill and confidence, and fill an empty niche in the team. This extends more to simple coding skills also: contributors can also be involved in planning, design, testing, research, code review, mentorship, and even leadership, taking some of the burden from your own shoulders. A good leader sees the potential in each contributor to grow in these domains, and figures out how to help them achieve that growth.</p> <p>As software engineers, we&rsquo;re used to applying our skills to technical problems, writing code, designing systems, and so on; but applying our problem-solving mindset to other domains as well will often yield surprisingly powerful results. When applied to the project&rsquo;s social problems, leadership emerges. Success in this respect allows you to scale your engineering output <em>exponentially</em>.</p> <p><strong>Advertisement:</strong> SourceHut&rsquo;s <a href="https://sourcehut.org/consultancy">free and open-source software consultancy</a> specializes in this kind of work. We provide not only talented engineers, but talented leaders. As the maintainers of dozens of FOSS projects, we are used to bringing out the best in ad-hoc teams of mixed experience, and our skills in mentorship and project management leaves that team stronger than it was when we started. Our work with upstream FOSS projects also has us constantly introducing ourselves to new projects and teams, and that experience has enabled us to execute on unfamiliar projects faster than anyone else. If that sounds like something that you need, <a href="mailto:[email protected]">get in touch</a>.</p> What's cooking on Sourcehut? July 2021 https://sourcehut.org/blog/2021-07-15-whats-cooking-july-2021/ Thu, 15 Jul 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-07-15-whats-cooking-july-2021/ <p>Hallo uit Nederland! Today&rsquo;s &ldquo;What&rsquo;s cooking&rdquo; is brought to you from Amsterdam, where I moved to at the start of the week. Due to this, I have had less time available for work, but there has been some new progress regardless. User signups haven&rsquo;t slowed, for one: we now have 23,670 users, some 442 greater than June. Please show them your hospitality and help them learn about sourcehut!</p> <p>The usual Mumble meeting for this month is, sadly, cancelled. I do not have the necessary equipment to participate yet. I&rsquo;ll see you for the August meeting instead.</p> <p>The only substantial improvement this month has been in lists.sr.ht, though it is not yet visible: the GraphQL API. I had hoped to ship it earlier, but it will be delayed for perhaps another week or two due to issues moving abroad. Progress has been significant in any case, and it is almost complete.</p> <p>Outside of this, various small bug fixes and maintenance work has landed throughout the services. Once I&rsquo;m settled into my new home, I expect progress to resume at a normal pace.</p> What's cooking on Sourcehut? June 2021 https://sourcehut.org/blog/2021-06-15-whats-cooking-june-2021/ Tue, 15 Jun 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-06-15-whats-cooking-june-2021/ <p>Halfway through 2021! Things are on-track for my hopes to have the beta ship this year. Joining us on the way are 23,228 users, of which 640 are new this month. Remember to be patient with them as they learn the ins and outs of using sr.ht!</p> <p>This month&rsquo;s Mumble meeting will take place on the normal date tomorrow, June 16th, at 16:00 UTC. We&rsquo;ll be on voice.mnus.de, port 64738, in the sourcehut room.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>I have overhauled the registration workflow in preparation for the future billing changes for the beta, more clearly distinguishing between the &ldquo;contributor&rdquo; approach and the &ldquo;maintainer&rdquo; approach — only the latter ultimately being expected to pay for their account. I&rsquo;ve also made some improvements for admins of third-party instances to make it easier to provide billing support following the changes to builds.sr.ht payment.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Mandatory payment is now in effect for all builds.sr.ht usage, for all users. If you require financial assistance, please <a href="mailto:[email protected]">email me</a> explaining your circumstances and you will be issued free service credits.</p> <p>As promised, the writable GraphQL API has shipped, allowing you to use GraphQL to submit jobs, manage job groups, and work with secrets.</p> <p>Additionally, thanks to Michael Forney&rsquo;s finishing touches on the old patchset, the NetBSD image is now available as &ldquo;netbsd/9.x&rdquo; (aka &ldquo;netbsd/latest&rdquo;) and &ldquo;netbsd/8.x&rdquo;. Furthermore:</p> <ul> <li>Fedora 35 is now available</li> <li>NixOS 21.05 is now available, and 20.03 has been removed</li> <li>OpenBSD 6.9 is now available, and 6.7 has been removed</li> <li>Minor improvements have been made to Arch Linux</li> </ul> <h2 id="listssrht">lists.sr.ht</h2> <p>The initial draft of the planned lists.sr.ht GraphQL API has been written, and you can <a href="https://git.sr.ht/~sircmpwn/lists.sr.ht/tree/api/item/api/graph/schema.graphqls">read it here</a> (send feedback to IRC). Additionally, Simon Ser has broken ground on <a href="https://git.sr.ht/~emersion/go-emailthreads">go-emailthreads</a>, which we hope to use to provide more robust email discussion parsing for future improvements to code review tooling. Developing this GraphQL API is our focus for the coming weeks.</p> SourceHut is leaving Freenode https://sourcehut.org/blog/2021-05-19-liberachat/ Wed, 19 May 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-05-19-liberachat/ <p>SourceHut has been a proud user of the Freenode IRC network since its inception. Today we have five sr.ht-related IRC channels for end-user support, operational monitoring, staff coordination, and more.</p> <p>We will be moving our channels to <a href="https://libera.chat">Libera Chat</a>, effective today. You can connect at irc.libera.chat on port 6697 (with SSL) and join us in #sr.ht.</p> <p>The Freenode network we once loved is the victim of a hostile takeover by corporate interests. We entirely reject the illegitimate new leaders who have used legal threats and back-room deals to steal the network. The dedicated volunteers at the heart of Freenode&rsquo;s success — the staff — have left for Libera Chat. We are sad to hear news of Freenode&rsquo;s fall, but proud to be following them, our friends and colleagues, to this new network.</p> <p>I&rsquo;ll see you there!</p> <p><strong>Update 2021-05-25</strong>: The new staff at Freenode have been re-opening channels which moved to Libera.chat, including #sr.ht. I have re-closed this channel and will re-iterate in no uncertain terms that sourcehut has left Freenode for good. Any channels you see on Freenode which proport to represent sourcehut are not endorsed by this organization.</p> What's cooking on Sourcehut? May 2021 https://sourcehut.org/blog/2021-05-16-whats-cooking-may-2021/ Sun, 16 May 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-05-16-whats-cooking-may-2021/ <p>Running a day late on this one — was travelling all day yesterday. We&rsquo;ll also be moving the Mumble meeting to tomorrow, May 17th, this month. Thanks for your patience! Today, SourceHut has 22,588 users, 698 more since the last status update. Please offer our new colleagues a warm welcome, and be patient with them as they learn how to use the software.</p> <p>The monthly Mumble meeting, one day later than usual, will take place at 16:00 UTC on May 17th, in the SourceHut room on voice.mnus.de, port 64738.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>In addition to the <a href="https://man.sr.ht/ops/builds.sr.ht-migration.md">recent billing changes</a>, builds.sr.ht saw the initial release of its <a href="https://man.sr.ht/builds.sr.ht/graphql.md">GraphQL API</a> this month! The current version is read-only, but I expect to ship the read/write API within the next few days — it&rsquo;s just finishing up the code review process now. You can take the builds.sr.ht GraphQL API for a test drive on the <a href="https://builds.sr.ht/graphql">GraphQL playground</a>.</p> <h2 id="graphql-update">GraphQL update</h2> <p>Today, we have the following GraphQL APIs working in production:</p> <dl> <dt>meta.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write</dd> <dt>git.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write</dd> <dt>hg.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>todo.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>builds.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-danger">✗</strong> write (soon)</dd> <dt>lists.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>hub.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>dispatch.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>paste.sr.ht</dt> <dd><strong class="text-danger">✗</strong> read <strong class="text-danger">✗</strong> write</dd> <dt>pages.sr.ht</dt> <dd><strong class="text-success">✓</strong> read <strong class="text-success">✓</strong> write</dd> </dl> <p>The next service to receive its GraphQL API will be lists.sr.ht. Ludovic has also been working on an hg.sr.ht GraphQL API, which I&rsquo;ll be helping out with soon. The project hub and write support for todo will be the last major projects for the GraphQL effort. After these, the remaining services — paste and dispatch — will be pretty straightforward.</p> <p>Following the completion of the initial APIs work, the plan is to design and implement a few other features which will be shared between all of these services, most notably GraphQL-native webhooks.</p> <p>I appreciate your patience while this work is ongoing. I know that there has not been much work in the realm of user-facing features over the past several months while we&rsquo;ve been focusing on getting this done. This work, when completed, will unblock a lot of the workstreams you&rsquo;ve been waiting for — organizations, improvements to the project hub and service interconnectivity, better ACLs, and so on. The GraphQL services are much more robust and sustainable for sr.ht, and will provide a necessary foundation for future features like these. It&rsquo;s not flashy, but paying down our tech debt is a necessary pain before we can start the beta.</p> Sourcehut is the fastest. So what? https://sourcehut.org/blog/2021-05-08-sourcehut-is-the-fastest-who-cares/ Sat, 08 May 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-05-08-sourcehut-is-the-fastest-who-cares/ <p>I&rsquo;m writing this from 10,000 meters above the Pacific Ocean<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, typing it into a $200 ARM laptop, and I have had a pretty productive workday so far. In fact, with 600-1200ms latency, frequent network drop-outs, and bandwidth which would make a circa-2008 2G network hang its head in shame, I have had endured hardly any discernible difference from my workflow at home.</p> <p>By objective measures, <a href="https://forgeperf.org">sourcehut is the fastest and most lightweight software forge</a><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> by a wide margin. I am able to load a git repository on git.sr.ht in about 3 seconds (DOM ready in 1.8s), while GitHub took 38 seconds (DOM ready in 20s)<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. Working with any of the sourcehut services — browsing git repos, reading and filing tickets, reviewing build logs — is hardly any different in this situation than it is at my workstation at home. Browsing any other forge, on the other hand, is miserable. In the same amount of time I can load 3 pages on GitHub (one full minute!), I can load more than 30 on sourcehut.</p> <p>That&rsquo;s just the network conditions, too. Recall that I mentioned I&rsquo;m on a cheap ARM laptop, basically a mid-tier chromebook. SourceHut has no mandatory JavaScript, and the pages are very light — almost all of them load in two requests or less, and usually transfer less than 10 KiB, even on a cold cache. It&rsquo;s easy to render and use sr.ht on any class of hardware. It works half decently in Lynx!</p> <p>All of that being said, I have only actually used the web services for three or four quick tasks today. SourceHut embraces open standards like email for collaboration. There is no suffering through the pull request review web UI on a craptop with a terrible connection. Patches arrive via email, and I have my mailbox stored locally in a standardized format, which I can read with simple text-based tools, then queue up my review as an emailed reply to be sent asynchronously whenever the network is up for it.</p> <p>For my part, this is a story that comes from privilege. I am in a self-imposed network drought on an expensive airplane fare, and sourcehut&rsquo;s performance is simply temporarily convenient. But there are a lot of people for whom this performance is an essential necessity in their daily life. This $200 craptop represents a substantial investment for a lot of people. The luxurious network conditions the developed world enjoys are just that: a developed luxury. I don&rsquo;t find these users less important simply because their constraints are harder to work in. We pride ourselves on thriving under those constraints.</p> <p>That ethos pays returns in many ways, like when I&rsquo;m sitting here on an airplane conducting my work without interruption, or when our simpler HTML is easier to use for the new developer on your team who has to rely on a screen reader. Though at first it may seem that our performance metrics are a flashy footnote, they represent something of real importance to us and to our users, and I hope that the rest of the web catches up with us soon.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>Fully vaccinated, and wearing a mask, and with a negative COVID-19 test result taken two days ago, for the record.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>These tests are conducted by sourcehut, but are based on independent measurement factors, have held up under independent scrutiny, and are open to improvements from the rest of the community.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:3"> <p>I can get on with my work after the DOM loads, but it&rsquo;s still asking my browser to suck down images, leeching what precious little bandwidth I have, taking it away from anything else I&rsquo;m trying to do.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> Bug trackers are for tracking bugs https://sourcehut.org/blog/2021-04-29-bug-trackers-are-for-bugs/ Thu, 29 Apr 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-04-29-bug-trackers-are-for-bugs/ <p>There&rsquo;s a reason that we call our bug tracking software &ldquo;todo&rdquo;: it designed to track things that need to be done. It&rsquo;s <em>not</em> designed for end-user support, handling feature requests, and so on. This is a departure from the approach of some other popular forges.</p> <p>We use our bug trackers for confirmed bugs and confirmed feature requests only. Due to learned behaviors from other platforms, many users do not understand this. For this reason, many project admins actually go so far as to set up read-only trackers, so that only maintainers can file tickets. This approach improves the quality of bug reports and sharply reduces duplicates, turning the tracker into a narrowly-focused tool for organizing the work of the contributors.</p> <p>But what happens to end-users in this arrangement? They&rsquo;re not forgotten: they are given a better venue for their problems. Most projects of this sort provide a foo-users or foo-discuss mailing list, which encourages submissions from end-users in a more forum-oriented style. Sometimes these discussions become actionable, in which case a ticket is filed by a maintainer or a janitor (the latter opening up a new contributor role for non-programmers), but more often than not the user just has to have a few questions answered. Often the answers come from other users, saving the maintainers time and encouraging a community of mutual support to develop.</p> <p>Many projects also set up an IRC channel for short questions, discussions, and hands-on troubleshooting in a real-time format. Many of the discussions on IRC can also result in tickets, or help collect information to start a good mailing list thread, and provide another role still for non-programming contributors to help others out. We&rsquo;ll soon be offering tools on sourcehut to help you maintain your project&rsquo;s IRC channel.</p> <p>In addition to this -users mailing list, most projects have a -devel mailing list for development discussions and patch reviews, and often a developer IRC channel as well. This segregation of development resources and end-user support resources helps developers stay focused and on-topic in their work, without interruption, and provides a <em>better</em> places for end-users to get help.</p> What's cooking on SourceHut? April 2021 https://sourcehut.org/blog/2021-04-15-whats-cooking-april-2021/ Thu, 15 Apr 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-04-15-whats-cooking-april-2021/ <p>Hello again! As another month rolls on by, sr.ht saw 849 new users join our ranks, bringing our total to 21,890. As always, please treat our new colleagues with patience while they learn the ropes.</p> <p>Tomorrow&rsquo;s monthly Mumble meeting is planned for 16:00 UTC, in the usual place: voice.mnus.de, port 64738. An important question will be discussed: should builds.sr.ht be made available only to paid sr.ht users? For details, see the builds.sr.ht update further on.</p> <h2 id="general-news">General News</h2> <p>First, and most importantly, I have some urgent news.</p> <p><img src="https://l.sr.ht/Xcj3.jpg" alt=""></p> <p>After ~nelson had some issues using Stripe from the Falkland Islands, I offered to accept payment for his sr.ht account in the form of cute pictures of the locals. He agreed, and here they are 🐧 He sent four pictures (<a href="https://l.sr.ht/pCOs.jpeg">[1]</a> <a href="https://l.sr.ht/Q9c-.jpeg">[2]</a> <a href="https://l.sr.ht/ajCP.jpeg">[3]</a> <a href="https://l.sr.ht/yUYU.jpeg">[4]</a>), and three videos (<a href="https://spacepub.space/videos/watch/ffcafcf2-a3e3-4996-b369-1bfdbbe640d5">[1]</a> <a href="https://spacepub.space/videos/watch/01bfa6e5-bf6a-4165-9c87-7a707dd9bc95">[2]</a> <a href="https://spacepub.space/videos/watch/f86f96be-2324-4381-96ee-47fd87c771e3">[3]</a>). Thanks, Nelson! Naturally, he will not be expected to pay for his account.</p> <p>Otherwise, things have been somewhat quiet, as (1) I&rsquo;ve taken a little bit of time off this month, and (2) we&rsquo;ve been busy warding off attackers at the gates. Otherwise, we have been working quietly on builds.sr.ht&rsquo;s GraphQL API.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>This is not a new feature, but a couple of weeks ago, I made a short video demonstrating how to use git.sr.ht&rsquo;s web patchset tools.</p> <iframe width="560" height="315" sandbox="allow-same-origin allow-scripts allow-popups" src="https://spacepub.space/videos/embed/ad258d23-0ac6-488c-83fc-2bacf578de3a" frameborder="0" allowfullscreen></iframe> <h2 id="buildssrht">builds.sr.ht</h2> <p>The GraphQL API is making good progress, and I hope to have the initial version online this month — only a few features left. Ignas Kiela has been working on some improvements for performance, and a few other minor improvements have shipped alongside those.</p> <p>Image updates:</p> <ul> <li>FreeBSD 13 is now available</li> </ul> <p>We&rsquo;ve been dealing with a rash of cryptocurrency mining attacks on builds.sr.ht this month, as you may have seen on <a href="https://status.sr.ht">status.sr.ht</a>. If you&rsquo;ve experienced long queue times, this is why: we are playing a cat &amp; mouse game trying to teach our systems to detect crypto miners, then updating them again after the attackers figure out how to work around them and saturate our build queue with cryptocurrency miners.</p> <p>We seem to have things under control for now, but it raises a more interesting question: should we just make builds.sr.ht a paid service? Ultimately, all sr.ht services are going to require payment, but builds is both the most expensive service for us to host, and the most ripe for abuse, so it may make sense to make it paid in ahead of the beta plans. We&rsquo;ll be discussing this idea with the community during the Mumble call tomorrow, feel free to join if you have some thoughts around this.</p> What's cooking on SourceHut? March 2021 https://sourcehut.org/blog/2021-03-15-whats-cooking-march-2021/ Mon, 15 Mar 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-03-15-whats-cooking-march-2021/ <p>Hi! Another month of development has passed, and I&rsquo;m here to fill you in on what&rsquo;s new. Another 686 signups this month has brought us to 21,041 users. As always, I&rsquo;ll be counting on you to make the new users feel at home, please be patient with them and help them learn the ropes.</p> <p>Last month, something suddenly came up and I had to skip the monthly Mumble call unannounced — my apologies! We&rsquo;ll be holding the meeting as scheduled tomorrow at 16:00 UTC at voice.mnus.de, port 64738, in the sourcehut room.</p> <h2 id="pagessrht">pages.sr.ht</h2> <p>The big news this month is that we shipped <a href="https://sourcehut.org/blog/2021-02-18-sourcehut-pages/">sourcehut pages</a>, which provides static hosting for websites and Gemini capsules. 282 users have created a site with it so far — you should check it out, too! Getting a website published only takes a couple of minutes.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>todo.sr.ht&rsquo;s initial GraphQL API is now available. Check out the <a href="https://todo.sr.ht/graphql">playground</a> here and our <a href="https://man.sr.ht/graphql.md">GraphQL docs</a> if you&rsquo;re not already familiar with how it works.</p> <p>Next up is&hellip;</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>The GraphQL API for builds.sr.ht is now underway. This one is quite welcome, as builds.sr.ht is our oldest sr.ht API and the most in need of an upgrade. It will also give us some opportunities to improve security for builds.</p> <h2 id="project-hub">Project hub</h2> <p>A minor update for the project hub this month: popular tags are now shown on the <a href="https://sr.ht/projects">public index</a>.</p> Sourcehut pages https://sourcehut.org/blog/2021-02-18-sourcehut-pages/ Thu, 18 Feb 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-02-18-sourcehut-pages/ <p>I&rsquo;m happy to announce that a long-awaited feature is available today: <a href="https://srht.site">sourcehut pages</a>. SourceHut users can use this service to host static websites for any of their own domains, and every user is also being given &ldquo;username.srht.site&rdquo;.</p> <p>Update: <a href="gemini://srht.site">gemini support</a> is now available as well!</p> <p>You can use any static site generator: Jekyll, Hugo, Doxygen, or your own cool new thing. You can publish from git.sr.ht or hg.sr.ht, or you can set up any publishing workflow you prefer — you just need to upload a tarball. Every domain has TLS automatically configured for you. You get your personal subdomain on srht.site, unlimited bring-your-own-domains, and up to 1G of storage per site.</p> <p>Check out <a href="https://srht.site">srht.site</a> for the full details, but here are some shell commands you can run right now to be live in 3 minutes.</p> <p>First, generate a <a href="https://meta.sr.ht/oauth2/personal-token">personal access key</a> and add it to your environment, something like this:</p> <pre tabindex="0"><code>bearer_token=9SKUndgx8Fx55xYGNAxs1Lal8YQAh29/90m+HjsMVsA= </code></pre><p>Then write a simple &ldquo;index.html&rdquo; file:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!doctype html&gt;</span> </span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span> </span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span> <span class="p">/&gt;</span> </span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My sourcehut page<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span> </span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>My sourcehut page<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span> </span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>Welcome to my cool sourcehut page! </span></span></code></pre></div><p>Put it in a tarball:</p> <pre tabindex="0"><code>tar -cvz index.html &gt; site.tar.gz </code></pre><p>And publish it, being sure to replace &ldquo;username&rdquo; with your sr.ht username:</p> <pre tabindex="0"><code>curl --oauth2-bearer &#34;$bearer_token&#34; \ [email protected] \ https://pages.sr.ht/publish/username.srht.site </code></pre><p>Hey presto, your new website is live! <a href="https://srht.site">Check out the rest of the documentation</a> for tips on automating this process, setting up a static site generator like Hugo, and how to use your own domain name.</p> <p>All sr.ht pages sites have some limitations to make them good internet citizens:</p> <ul> <li>HTTPS is required</li> <li>All third party resources, including Google Analytics, are blocked</li> <li>CloudFlare&rsquo;s reverse proxy is blocked</li> </ul> <p>So everyone who visits a sr.ht page can be confident that everything is above board. Enjoy!</p> What's cooking on Sourcehut? February 2021 https://sourcehut.org/blog/2021-02-15-whats-cooking-february-2021/ Mon, 15 Feb 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-02-15-whats-cooking-february-2021/ <p>Greetings! I&rsquo;m happy to share that our community has surpassed 20,000 users this month. 708 new faces have joined our ranks, bringing the total to 20,355. We&rsquo;ve become a pretty big community! Please be friendly and patient with them as they learn the ropes. This month&rsquo;s &ldquo;what&rsquo;s cooking&rdquo; is somewhat deficit in interesting user-facing developments, but I will dutifully report our progress nonetheless.</p> <p>Our next public Mumble conference will be held tomorrow at 16:00 UTC, on voice.mnus.de, port 64738, in the sourcehut room. Feel free to join us to share your thoughts and ask your questions. I&rsquo;ll <span style="text-decoration: line-through">see you</span> hear you there!</p> <h2 id="general-news">General news</h2> <p>We&rsquo;ve upgraded (most of) our infrastructure to Alpine Linux 3.13, and made sr.ht packages available to any admins who are running third-party instances. A quick reminder that any such admins should be subscribed to the <a href="https://lists.sr.ht/~sircmpwn/sr.ht-admins">sr.ht-admins</a> mailing list to receive this and other important announcements that affect your instance.</p> <p>We will have to schedule a second round of upgrades for our hardware hosts sometime in the next few weeks. It&rsquo;ll be announced in advance on sr.ht-announce and on status.sr.ht when the time comes.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Most of our progress this month is in the new todo.sr.ht GraphQL API, which is going well. I hope to ship an initial read-only version to production before the next status update.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Not technically an update for builds.sr.ht, but rather for the software which submits build manifests: we&rsquo;ve started developing some standard environment variables which are set by git.sr.ht, hub.sr.ht, and so on, when submitting builds. You can use these to programmatically find out why your build was submitted, and access other context-specific details. <a href="https://man.sr.ht/builds.sr.ht/#integrations">Check out the docs here</a>.</p> What's cooking on Sourcehut? January 2021 https://sourcehut.org/blog/2021-01-15-whats-cooking-january-2021/ Fri, 15 Jan 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-01-15-whats-cooking-january-2021/ <p>Another year begins, and hopefully with better prospects for us all. SourceHut has emerged from 2020 relatively unscathed, thankfully, and I hope the same is true of most of our users. A body which, by the way, today numbers 19,647 strong, up 623 from December. Please warmly welcome our new members, and be sure to lend them your expertise as they learn how to use our tools.</p> <p>Tomorrow&rsquo;s public Mumble conference will be held at 16:00 UTC, on voice.mnus.de, port 64738, in the sourcehut room. Feel free to join us to share your thoughts and ask your questions. See you there!</p> <h2 id="general-news">General news</h2> <p>First, a much asked-for feature is now available: a dark theme! I actually rolled out the first roll on this feature a few hours after publishing last month&rsquo;s status update. It is enabled automatically when your user-agent requests it via <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-color-scheme: dark</a>. A few iterations of improvements have already been performed, and we are keeping a list of matters for attention in future patches, but please feel free to share your feedback on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a> as you encounter any issues.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>As promised, we broke ground on API 2.0 for todo.sr.ht this month. Feel free to check out the <a href="https://git.sr.ht/~sircmpwn/todo.sr.ht/tree/api/item/api/graph/schema.graphqls">draft GraphQL schema</a> if you are curious to know more.</p> <h2 id="hgsrht">hg.sr.ht</h2> <p>Following the roll-out of git.sr.ht&rsquo;s API 2.0 implementation, Ludovic Chabant has been hard at work on developing a prototype of an API 2.0 branch for hg.sr.ht as well. I intend to review this and help form it into a production-ready implementation in the coming weeks.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>Small news: you can now update the patchset revision in the patch preparation UI. Nolan Prescott also contributed some fixes to this workflow for some missed edge cases.</p> <h2 id="dispatchsrht">dispatch.sr.ht</h2> <p>An experimental feature is now available which allows dispatch.sr.ht users to forward patches sent to a lists.sr.ht mailing list to GitLab as merge requests, and convey the enusing discussions between both mediums. YMMV.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>There have been some minor fixes and improvements to the following images:</p> <ul> <li>Debian</li> <li>Fedora</li> <li>NixOS</li> </ul> <p>Additional Fedora improvements are in the pipeline, as well as a new Void Linux image.</p> On the subject of ethics in our industry https://sourcehut.org/blog/2021-01-13-regarding-ethics/ Wed, 13 Jan 2021 00:00:00 +0000 https://sourcehut.org/blog/2021-01-13-regarding-ethics/ <p>I am disappointed by our peers in the industry in terms of their failure to uphold a reasonable moral standard, and I am sorry that it is necessary for me to write about it today. I would much prefer that we compete in terms of our product&rsquo;s utility and our technological expertise, and it shames me that we must also compete in terms of our respective levels of command over our moral compasses.</p> <p>I learned today of an incident at GitHub, one of our competitors.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> A Jewish employee was fired in apparent retaliation for commenting &ldquo;stay safe homies, Nazis are about&rdquo; in one of the company&rsquo;s Slack channels. This occurred during an insurrection at the US Capitol by radical right-wing, racially-motivated terrorists, at least some of whom were wearing Nazi propaganda, for the purpose of uprooting the democratic process to install a fascist demagogue. The seditionist riot claimed lives.</p> <p>This news comes months after GitHub made the news for accepting contracts<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> with US Immigration and Customs Enforcement, an organization which has infamously committed large-scale human rights violations at the behest of that same fascist demagogue, problems which were generally known at the time and which were brought to GitHub&rsquo;s attention without effect. Around the same time, another company in the same space, GitLab, loosened their internal policies<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> to make it easier for them to make similar agreements without regard to ethics, stating that they will, quote, do business with &ldquo;customers with values that are incompatible with our own values.&rdquo;</p> <p>This level of moral absenteeism within the industry SourceHut shares astonishes me. I wish that there was no need for me to make the following statements explicitly.</p> <p>These are the official policies of SourceHut: we condemn white nationalism, Donald Trump, and the supporters of both. We affirm that we value human rights, the democratic process, and the judicial process. We assert the rights and value of all people, of all nationalities, races, ethnicities, sexual preferences, gender identities, disabilities, religions, and economic classes. We will defend anyone who would speak up in support of these ideals. We will not do business with anyone who does not recognize and embody these truths.</p> <p>We think it&rsquo;s repugnant that our peers don&rsquo;t demonstrate the same values. We think that you, the customer, should reward businesses that commit to upholding these values with your patronage, and withhold it from those which will not.</p> <p>Also, in case the employee that GitHub terminated is reading this: <a href="mailto:[email protected]">feel free to get in touch</a> if you&rsquo;re still open to a job in the industry. We&rsquo;d be happy to talk to you.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>Source: <a href="https://www.businessinsider.com/microsoft-github-backlash-jewish-employee-termination-2021-1">Business Insider</a> (alternate without paywall: <a href="https://gizmodo.com/github-fired-a-jewish-employee-for-warning-that-nazis-1846047140">Gizmodo</a>)&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>Source: <a href="https://www.bloomberg.com/news/articles/2019-10-10/microsoft-employees-call-to-end-github-ice-contract">Bloomberg</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:3"> <p>Source: <a href="https://www.theregister.com/2019/10/16/gitlab_employees_gagged/">The Register</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on Sourcehut? December 2020 https://sourcehut.org/blog/2020-12-15-whats-cooking-december-2020/ Tue, 15 Dec 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-12-15-whats-cooking-december-2020/ <p>A brisk wind of winter chill sets a stir down my spine, as I sit down with a fresh cup of coffee to yarn a story of careful engineering and passionate spirit that took place over the course of 30 days. The last 30 days. Cause this is the monthly &ldquo;what&rsquo;s cooking&rdquo; post. Welcome! This month we&rsquo;re joined by 815 new users, bringing the total to 19,024. Please give them your warmest welcome and help them learn the ropes.</p> <p>Our next public Mumble conference will be held tomorrow at 16:00 UTC, on voice.mnus.de, port 64738, in the sourcehut room. Please join us to share your feedback, ask questions, and so on.</p> <h2 id="general-news">General news</h2> <p>The big news this month is the rollout of API 2.0 support for meta.sr.ht and git.sr.ht, both of which have reached feature parity with their REST counterparts. For meta.sr.ht as well, our new OAuth 2.0 backend has shipped and is fully compliant with RFC 6749.</p> <p>todo.sr.ht is up next, and work for API 2.0-native webhooks is going to begin soon as well.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>Here are the resources for meta.sr.ht&rsquo;s GraphQL support:</p> <ul> <li><a href="https://man.sr.ht/graphql.md">GraphQL documentation</a></li> <li><a href="https://meta.sr.ht/graphql">meta.sr.ht playground</a></li> <li><a href="https://man.sr.ht/meta.sr.ht/oauth.md">OAuth 2.0 documentation</a></li> </ul> <p>There were also some improvements to our abuse prevention capabilities after a wave of spam registrations — if any third-party sr.ht admins require similar interventions for their instances, please reach out in private.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>git.sr.ht&rsquo;s GraphQL API grew support for mutations, like repository creation and artifact uploads. Resources:</p> <ul> <li><a href="https://man.sr.ht/graphql.md">GraphQL documentation</a></li> <li><a href="https://git.sr.ht/graphql">git.sr.ht playground</a></li> </ul> <h2 id="listssrht">lists.sr.ht</h2> <p>Email replies to patchset threads can now include a custom header, <code>X-Sourcehut-Patchset-Update</code> to update the status of the patchset to ACCEPTED, REJECTED, NEEDS_REVISION, and so on. Additionally, a couple of buttons have been added to all mailing lists which allow any user — list admin or not — to download an archive of either the last 30 days, or the entire list&rsquo;s history, as an mbox for importing into their local mail spool.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>NixOS 19.09 has been removed following its upstream deprecation.</p> SourceHut's second year in alpha https://sourcehut.org/blog/2020-11-15-sourcehut-2-year-alpha/ Sun, 15 Nov 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-11-15-sourcehut-2-year-alpha/ <p>Today is the second anniversary of <a href="https://drewdevault.com/2018/11/15/sr.ht-general-availability.html">SourceHut being made available to the general public</a> during its alpha phase of development, and the end of the fourth year of development. What a year it&rsquo;s been! If only I could send a warning to the younger me who wrote <a href="https://sourcehut.org/blog/2019-11-15-sourcehut-1-year-alpha/">last year&rsquo;s article</a>. As the second anniversary comes around, despite the trials we&rsquo;ve endured this year, I feel positive about our accomplishments.</p> <p>One year ago, I wrote that I expected SourceHut to enter its beta phase in 2020, and I was wrong. However, we do have a well-defined, finite list of action items to be completed before we can kick off the beta. We hit a lot of important development milestones this year, and we&rsquo;ll put the cherry on top in 2021.</p> <p>This month&rsquo;s public Mumble conference will take place tomorrow (the 16th) at 17:00 UTC, in the sourcehut room on voice.mnus.de, port 64738. Please join us to celebrate our second year, and ask any questions or provide any feedback that you might have about sourcehut.</p> <p>Let&rsquo;s take a moment celebrate our accomplishments in 2020, and lay out our plans for 2021.</p> <h2 id="2020-in-summary">2020 in summary</h2> <p>Here are some of the more important things we got done:</p> <ul> <li>The project hub</li> <li>Initial GraphQL APIs for meta.sr.ht, git.sr.ht</li> <li>git.sr.ht release artifacts, git blame &amp; path logs</li> <li>builds.sr.ht job artifacts, RSS feeds</li> <li>lists.sr.ht CI integration</li> <li>todo.sr.ht tracker data import/export</li> <li><a href="https://man.sr.ht/ops">Public access</a> to operations data &amp; documentation</li> </ul> <p>And some of the numbers for 2020:</p> <ul> <li>7,344 users signed up</li> <li>1,447 mailing lists established; 37,164 emails sent</li> <li>2,024 bug trackers and 9,210 tickets filed</li> <li>15,754 git repositories and 2,662 hg repositories made</li> <li>233,000 build jobs completed</li> <li>2× increase in revenue</li> </ul> <p>And, 2,000 projects on the brand-new project hub! You can browse <a href="https://sr.ht/projects">the 723 public projects right here</a>. Some notable projects which started using SourceHut this year include:</p> <ul> <li>Dozens of <a href="https://sr.ht/projects?search=%23gemini">Gemini projects</a> started on sr.ht this year</li> <li>sr.ht is the home of <a href="https://sr.ht/projects?search=%23plan9">the Plan 9 renaissance</a></li> <li>The <a href="https://git.sr.ht/~alextee/zrythm">Zrythm</a> Digital Audio Workstation moved in</li> <li><a href="https://sr.ht/~martanne/vis/">vis</a> and <a href="https://sr.ht/~kevin8t8/mutt/">mutt</a> set up sr.ht mirrors and CI</li> <li><a href="https://github.com/alacritty/alacritty/tree/master/.builds">alacritty</a> and <a href="https://github.com/nim-lang/Nim/tree/devel/.builds">Nim</a> rigged up our CI</li> <li>More in <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CC732POCJYTNF.3H7H6HK42HCJZ%40taiga%3E">this thread</a> and <a href="https://cmpwn.com/@sir/105208976033597297">this thread</a></li> </ul> <p>We&rsquo;ve also contributed to many FOSS projects upstream, including:</p> <ul> <li>git send-email improvements</li> <li>Mercurial patches</li> <li>Linux documentation patches</li> <li>New pygit2 and libgit2 features, and financial support</li> <li>musl financial support</li> <li>Redis vulnerability reported &amp; fixed</li> <li><a href="https://joinpeertube.org/">PeerTube</a> financial support</li> </ul> <p>And our engineers, under the open-ended directive of &ldquo;make FOSS better&rdquo;, have contributed to Wayland, Mesa, Vulkan, Go, the Linux kernel, IRCv3, <a href="https://gemini.circumlunar.space">Gemini</a>, and more. Our <a href="https://sourcehut.org/consultancy">FOSS consulting arm</a> has produced 100% free-software output in Mesa, Xorg, and more, and built a brand-new <a href="https://sr.ht/~migadu/alps">FOSS webmail</a>, for clients like Valve Software and Migadu.</p> <p><img src="https://l.sr.ht/7wYp.png" alt=""></p> <p><img src="https://l.sr.ht/uB2_.png" alt=""></p> <p><img src="https://l.sr.ht/Wuvf.png" alt=""></p> <p><img src="https://l.sr.ht/6gzm.png" alt=""></p> <h2 id="expectations-for-2021">Expectations for 2021</h2> <p>Well, I&rsquo;ll go ahead and make the same ill-fated prediction this year: the beta will begin sometime in 2021. One of the blockers I mentioned last year still remains to be completed — user groups/organizations — but the main blocker is the completion of <a href="https://sourcehut.org/blog/2020-09-25-api-2-updates/">API 2.0</a>. I&rsquo;ve also added &ldquo;beta&rdquo; labels to all of our <a href="https://todo.sr.ht/trackers/~sircmpwn?search=sr.ht">bug trackers</a>, if you want to explore the fine details of what features and bugs are considered blockers.</p> <p>The business and operational goals laid out in last year&rsquo;s post have been met. The only business-related blocker is determining how the long-promised pricing changes will take shape when the beta begins, which will be heavily influenced by the ultimate implementation of user groups. Of course, the community will be involved in every part of this discussion. And, as always, I&rsquo;ll re-iterate that the plan is not to price users out of the service — those who are unable to afford payments, as always, will be issued free service.</p> <p>The API 2.0 efforts are of particular importance for the beta. Their completion will be necessary to establish an API that we can be confident in supporting for many years into the future, and enable us to expand the services and their awareness of one another to any degree we please. The performance, scalability, and reliability of our services is also expected to increase substantially with the completion of API 2.0.</p> <p>We also made substantial progress on data ownership — you can now export and import almost all of your data on sourcehut, much of it in standard formats — but we also want to expand on this by implementing self-service account deletion and renames, and a unified solution for downloading all of your data at once.</p> <p>So, in short, we have this to look forward to for the beta:</p> <ul> <li>User groups/organizations</li> <li>API 2.0 completion</li> <li>Improvements to the cross-service awareness</li> <li>Completion of data ownership goals</li> </ul> <p>We still have a lot of work on the horizon, but we have a well-laid plan towards the finish line and the start of the beta phase. Once the beta begins, we&rsquo;ll focus on refining our model, flushing out bugs, improving our already <a href="https://forgeperf.org">best-in-class</a> performance and reliability, and establishing enough confidence in the system to declare it production ready.</p> <p>SourceHut has much higher standards for production readiness than most software. Many users are already enjoying SourceHut as the platform of choice for their own production-ready projects, and we already make stability and security guarantees which many would consider necessary as such. But we&rsquo;re not going to declare our system production ready until we&rsquo;ve well exceeded the standards of the industry — we want <em>the best</em> performance, <em>the best</em> reliability, and we want to leave a wide margin for everyone else to catch up. We&rsquo;re only going to declare it production ready when we&rsquo;re far ahead of the pack and prepared to support all of our features and users for decades to come. SourceHut will be &ldquo;production ready&rdquo; when it&rsquo;s prepared to become the bedrock of free software, and not before.</p> <h2 id="whats-cooking-on-sourcehut-november-2020">What&rsquo;s cooking on SourceHut? November 2020</h2> <p>Now, for your regularly scheduled status update, I&rsquo;ll keep it brief. Most of the work has been behind the scenes, on API 2.0.</p> <h3 id="metasrht">meta.sr.ht</h3> <ul> <li>gemini:// and gopher:// URLs are now permitted for profile URLs</li> </ul> <h3 id="buildssrht">builds.sr.ht</h3> <ul> <li>nixos/20.09 is now available</li> <li>openbsd/6.8 is now available</li> <li>ubuntu/20.10 is now available</li> <li>freebsd/12.x has been updated to FreeBSD 12.2</li> </ul> SourceHut Q3 2020 Financial report https://sourcehut.org/blog/2020-11-11-sourcehut-q3-2020-financial-report/ Wed, 11 Nov 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-11-11-sourcehut-q3-2020-financial-report/ <p>In summary, SourceHut is financially healthy. Our revenue is still growing, and we are still profitable and becoming more so. However, growth has slowed significantly compared to Q2. In internal terms, Q3 has been characterized by an increased emphasis on planning, less visible development efforts, and a decreased emphasis in marketing — not to mention taking place during a series of global and national crises — some or all of which may provide an explanation. Regardless, this may not be indicative of a trend, and we have still experienced positive growth by all accounts.</p> <small> Disclaimer: this report is a summarized approximation of our financials, and is not used for tax purposes. </small> <h2 id="revenue-sources">Revenue sources</h2> <p>Sourcehut receives revenue from paid user subscriptions. During Q3, we processed 1,855 invoices. The invoices paid break down as:</p> <pre tabindex="0"><code>1,007 $2 (paid monthly) 464 $5 (paid monthly) 155 $10 (paid monthly) 246 $2 (paid yearly) 57 $5 (paid yearly) 28 $10 (paid yearly) </code></pre><p>The total gross revenue during Q3 was $16,134, which after transaction fees is $14,972. This is very similar to our Q2 revenue, and a 213% increase over Q2 2019.</p> <p>In Q3, 1,850 new users registered for an account. Of these users, 199 are paid; 10.8%. These numbers are both somewhat lower than expected. Q2 saw 2,551 new registrations, and the usual conversion rate is 11.7%. It remains to be seen if this is a trend. As of November 11th, the breakdown is as follows:</p> <pre tabindex="0"><code> 344 $2 (paid monthly) 163 $5 (paid monthly) 58 $10 (paid monthly) 1,054 $2 (paid yearly) 337 $5 (paid yearly) 132 $10 (paid yearly) </code></pre><p>The monthly revenue from all subscriptions is, accounting for credit card fees and amortizing yearly payments, is $5,952. This is an increase of $408 in monthly revenue compared to Q2.</p> <p>SourceHut has $13,858 in cash at the time of writing.</p> <h2 id="expenses">Expenses</h2> <p>Breakdown of Q3 expenses:</p> <pre tabindex="0"><code>$4660 Servers and equipment $1950 Philadelphia datacenter lease (inc. network, power, etc) $300 pygit2 sponsorship $130 Domain name registration &amp; renewals $100 Regulatory fees $96 musl libc sponsorship </code></pre><p>Our main expense this quarter was for putting together a new server, sakuya1, which is our first second-generation VM hosting server. The costs fell within the expectations explained in the Q2 financial report. Presently this server is only used for hg.sr.ht, but its role will expand in the future.</p> <p>We do not have any unusual expenses planned for Q4.</p> Mailing lists are resistant to censorship https://sourcehut.org/blog/2020-10-29-how-mailing-lists-prevent-censorship/ Thu, 29 Oct 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-10-29-how-mailing-lists-prevent-censorship/ <p>As a US entity, SourceHut is obliged to comply with DMCA notices. In this event, our next step would likely be to coach the affected project through the counter-notice process, and contribute to their legal costs if we believe that they&rsquo;re in the right. We know that the DMCA is a constantly abused force for censorship, and there are no friends of the RIAA here. They represent much that our mission statement — to support and improve the free- and open-source software ecosystem — stands in opposition to.</p> <p>Even beyond our principles, however, the mailing list based workflow we espouse is resistant to this kind of censorship. Git repositories are easily re-hosted, of course. However, if a lot of your project&rsquo;s value requires rapid updates and the ongoing support of its development community, a centralized, pull-request-style system is vulnerable to censorship.</p> <p>If you use mailing lists, you might not even immediately notice that something was wrong. That contributions pass through a centralized mailing list is often only a formality — the project maintainers and others likely to have comments will usually be Cc&rsquo;d on the emails, and they&rsquo;ll be delivered directly to them without the list&rsquo;s help. Recipients can provide feedback by replying to the email, sending their comments directly to the contributor, and bypassing the mailing list entirely. The list faithfully records these emails and forwards them to interested parties, but it&rsquo;s not actually required for this to work.</p> <p>A mailing list also provides every maintainer, contributor, and onlooker a copy of everything which has happened on it. Like git distributes repositories to anyone working on them, mailing lists distribute a complete archive of the list to everyone who is subscribed to them. Taking this archive somewhere else and carrying on is effortless.</p> <p>Moreover, you would be hard pressed to make a strong argument that <em>new</em> patches could be covered by the DMCA, as they represent original additions to the codebase. We&rsquo;d consult our lawyers to consider the specific circumstances, but it&rsquo;s entirely possible that we wouldn&rsquo;t even have to shut off the mailing list when dealing with this situation. SourceHut&rsquo;s tools — bug trackers, mailing lists, git repos, and so on — can work independently of one other.</p> <p>Embracing decentralized, open standards like email and mailing lists is a good tool for censorship resistance. Putting all of your eggs into a basket controlled by a single corporate entity, who will be coerced by bullies and bad laws, is not a strategy for success. Times like these remind us why open source projects need to use open source infrastructure, built on open standards.</p> <p><em>Haven&rsquo;t used email with git before? Here&rsquo;s what it&rsquo;s like:</em></p> <iframe width="560" height="315" sandbox="allow-same-origin allow-scripts allow-popups" src="https://spacepub.space/videos/embed/1619c000-7c44-4330-9177-29a0854bd759" frameborder="0" allowfullscreen></iframe> <p><em>Check out <a href="https://git-send-email.io">git-send-email.io</a> to try an interactive tutorial.</em></p> What's cooking on Sourcehut? October 2020 https://sourcehut.org/blog/2020-10-15-whats-cooking-october-2020/ Thu, 15 Oct 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-10-15-whats-cooking-october-2020/ <p>Once again we meet to discuss the status of the ongoing SourceHut alpha, which has made progress by leaps and bounds this month. We&rsquo;re joined by 521 new users this month, bringing our total up to 17,715. As always, please welcome them warmly and show our new friends the ropes.</p> <p>Tomorrow, we&rsquo;ll be holding the second public Mumble conference, where you&rsquo;re welcome to join us to ask questions, share feedback, or just to listen in. We&rsquo;ll be meeting tomorrow, October 16th, at 16:00 UTC, in the SourceHut room on voice.mnus.de, port 64738. I&rsquo;ll see (or hear) you there!</p> <p>I mentioned last month that today would mark the second year of the sr.ht alpha — my mistake! It&rsquo;s actually next month. I&rsquo;ll put together a more detailed status update then which summarizes our progress this year and outlines the plans for next year. I should also have the Q3 financial report done by then.</p> <h2 id="general-improvements">General improvements</h2> <p>A few weeks ago I wrote <a href="https://sourcehut.org/blog/2020-09-25-api-2-updates/">a detailed log</a> going over the progress and planning for the API 2.0 efforts. OAuth 2.0 support has been completed, and most of the new database abstractions are done. Since that post, I&rsquo;ve also completed the work on asyncronous task management, and based on that also the necessary bits for legacy webhook delivery. This is the last blocker which prevents shipping the writable API into production even in an early form, as it would have caused inconsistency between services without. Accordingly, I expect to ship an early version of the writable meta.sr.ht GraphQL API into production in the next few weeks.</p> <p>We&rsquo;ve built a new ops tool this month called <a href="https://sr.ht/~sircmpwn/chartsrv">chartsrv</a>, which generates SVG plots from Prometheus data, like this live chart of the load average across builds.sr.ht workers:</p> <p><img src="https://metrics.sr.ht/chart.svg?title=Build%20worker%20load%20average&amp;query=avg_over_time%28node_load15%7Binstance%3D~%22cirno%5B0-9%5D%2B.sr.ht%3A80%22%7D%5B1h%5D%29&amp;max=64&amp;since=336h&amp;stacked&amp;step=10000&amp;height=3&amp;width=10" alt=""></p> <p>Thanks are also due to gildarts and Ignas Kiela this month, for their work adding links to Markdown headings throughout SourceHut, to allow users to easily obtain a link to a specific heading. Thanks folks!</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Debian users should be advised that an update to the Debian riggings is going to affect how packages are installed in a way which may break your builds. An email was sent to all users who have submitted Debian builds in the last 30 days with details, and another email will be sent out before the change is deployed, 15 days from now.</p> <p>Thorben Günther has also improved the Arch Linux images to make them faster and more reliable. Thanks!</p> <h2 id="todosrht">todo.sr.ht</h2> <p>наб added a user preference to todo.sr.ht this month which allows users to choose to have email notifications sent to them for their own activity on todo.sr.ht. Thanks наб! I have also fixed a minor issue with tracker import/export which may have affected users with older bug trackers.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>Thanks to Timothée Floure&rsquo;s work, meta.sr.ht now includes an LDAP authentication backend, which third-party installations of sr.ht may find useful for integrating with their existing authentication system. Thanks Timothée!</p> <h2 id="gitsrht">git.sr.ht</h2> <p>Thanks due to наб and Thorben Günther for small patches this month, respectively for improving symlinks and observability, and for fixing an issue with build submissions.</p> Post-mortem: git.sr.ht's almost-outage today https://sourcehut.org/blog/october-almost-outage/ Thu, 08 Oct 2020 00:00:00 +0000 https://sourcehut.org/blog/october-almost-outage/ <p>git.sr.ht <em>almost</em> suffered an outage today, when available disk space for repository storage got as low as 2.8 GiB. Thankfully, the problem was identified and a solution applied before an outage was incurred. This ended up being a good case study in the value of good monitoring and a solid understanding of the performance characteristics of your system. So, what caused this to happen, why <em>didn&rsquo;t</em> it cause an outage, and what have we learned?</p> <p><img src="https://sourcehut.org/git.sr.ht-disk-over-time.svg" alt="An SVG plot showing git.sr.ht free disk space over time, trending from 100G to less than 25G over 5 days"></p> <em style="text-align: center; display: block"> <small> A plot showing free disk space on git storage over 5 days. Higher is better. <br /> We generate these graphs with <a href="https://sr.ht/~sircmpwn/chartsrv" rel="noopener" >chartsrv</a>, by the way. </small> </em> <p>During a routine audit of our systems on September 18th, I discovered that git.sr.ht disk space was growing at a higher than expected rate. At the growth rate observed on the 18th, I estimated that we had 9 weeks before we&rsquo;d run out of disk space. Having other things to deal with at the time, <a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev/%3CC5QM8KFLQUHN.2796RCC83HBHA%40homura%3E">I wrote up my initial findings on the sr.ht-dev mailing list</a> and planned to re-visit the problem 3 weeks later.</p> <p>Run the clocks forward to last night, and a disk space usage alarm <a href="https://lists.sr.ht/~sircmpwn/sr.ht-ops/%3C1602078072831595278.11616517120117617331%40metrics%3E">goes off</a>. These fire when we reach 80% storage utilization on any host. Normally this incurs an immediate investigation, but I initially presumed that it was the natural progression of the growth trends we had observed a few weeks prior. I downgraded the urgency of the alarm and made a note to follow up this morning.</p> <p>So, this morning rolls around, and I log into the machine and check the disk usage&hellip; and there&rsquo;s only 4.6 GiB left, and falling by 2 gigs per hour! This trend is obviously heading towards disaster, so I quickly truncate some large log files to buy time, <a href="https://status.sr.ht/issues/2020-10-08-git.sr.ht-disk-usage/">file a public incident report</a>, and loop <a href="http://webchat.freenode.net/?channels=%23sr.ht&amp;uio=d4">#sr.ht</a> in on the issue.</p> <p>The game plan is:</p> <ol> <li>Establish a lower bound on disk space at which an emergency is declared and git.sr.ht is put into read-only mode. This is set at 2 GiB.</li> <li>Spin up a new server with sufficient storage space to accomodate the growth for long enough to re-evaluate our plans.</li> <li>Start transferring data over and get as much of the migration done as possible before hitting that 2 GiB floor and declaring an outage.</li> <li>Investigate: why is this happening?</li> </ol> <p>Steps 2 and 3 have some idle time baked in, so I&rsquo;m doing the investigation in parallel. It seems strange, there&rsquo;s no one adding especially large repos and the git storage growth rate is consistent with our normal projections. I ruminate over it while working on provisioning a replacement server. Once I&rsquo;m prepared to start the <code>zfs receive</code> to pull the dataset over to the new host&hellip; I notice that the snapshots are unusually large.</p> <p>I delete six old snapshots and immediately freed up 500 GiB of space. Crisis over.</p> <p><img src="https://sourcehut.org/git.sr.ht-snapshots-freed.svg" alt="A chart showing the before and after when the snapshots were deleted"></p> <p>An update is issued for the incident report: the issue was resolved without incurring an outage. Now comes the important questions:</p> <ul> <li>Why did this happen?</li> <li>How can we prevent it from happening again?</li> </ul> <p>This should not have happened. We are aware that snapshots occupy disk space and we had measured their growth rate and factored it into our planning for git.sr.ht disk space utilization. So why were they so large?</p> <p>The culprit ended up being that, on August 12th, <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/commit/b2ddc75f0b66debe09b7c6af4837b7817a1a018d">we deployed a cronjob which runs git-gc every 20 minutes on a random subset of git repositories</a>. Prior to this change, our git storage was basically append-only: outside of users deleting their repositories, objects were only ever added, not removed. After this change, we started to <em>delete</em> objects as well, which caused the rate at which differences between snapshots and the present filesystem accumulated to change, causing our snapshots to display a more pronounced increase in size as they aged. Our snapshot retention policy did not account for this different growth model.</p> <p>Our Prometheus retention policy was only set to 15 days (it has since been increased to 60 days), so we can&rsquo;t directly observe a change in the growth rate at the time this commit was deployed. However, we can observe that disk usage fluctuates periodically:</p> <p><img src="https://sourcehut.org/git.sr.ht-periodic-fluctuations.svg" alt="A graph showing periodic fluctuations in free disk space, trending downwards"></p> <em style="text-align: center; display: block"> <small>In this chart, a higher number means more free disk space.</small> </em> <p>The GC script runs every 20 minutes, and we take a snapshot every 15 minutes, hourly, and daily. With each GC, disk space frees up briefly, and is reduced again when a snapshot is taken.</p> <p>Now that we know the cause, we can plan to avoid this issue in the future. It&rsquo;s less urgent now that the emergency is resolved, but the future plans are to:</p> <ol> <li>Create fine-grained storage utilization metrics which correlates utilization with purpose, so we can see separate utilization figures for git storage, ZFS snapshots, logs, etc.</li> <li>Re-reason about our retention policy and storage utilization growth rate armed with new knowledge about the effect of git GC on storage utilization.</li> <li>Move forward with planning for normal git.sr.ht storage upgrades. We&rsquo;re planning on expanding storage 4x-8x in the foreseeable future.</li> <li>Add additional instrumentation to our cronjobs to better understand the role they play in system performance.</li> </ol> <p>I&rsquo;ve also increased the metrics retention from 15 to 60 days to allow us to better observe long-term trends and have a larger window for forensics. This shouldn&rsquo;t present a problem for storage on our monitoring system, but it monitors itself and will let us know if it starts to run out of space.</p> <p>So, crisis averted for today. Let&rsquo;s take this opportunity to improve our planning and observation skills to make sure that we&rsquo;re better prepared for tomorrow&rsquo;s crisis.</p> In-process work queueing for Go https://sourcehut.org/blog/go-work-queues/ Tue, 06 Oct 2020 00:00:00 +0000 https://sourcehut.org/blog/go-work-queues/ <p>In the course of our <a href="https://sourcehut.org/blog/2020-09-25-api-2-updates/">API 2.0 efforts</a>, it is necessary for us to implement some kind of mechanism for queueing and retrying work in our Go platform. The most obvious examples of this work is sending emails and delivering webhooks, but there are more subtle examples, too — just about anything which can be moved out of the request → response hot path would improve performance for the end-user. As such, some kind of task queue is called for.</p> <p>Our Python codebase uses <a href="https://docs.celeryproject.org/en/stable/getting-started/introduction.html">Celery</a>, and we have already had some experience at building Celery workers <a href="https://github.com/gocelery/gocelery">in Go</a>. However, on the whole we&rsquo;re pretty dissatisfied with Celery. It&rsquo;s too complicated and inflexible for our needs. Something lighter weight and more toolkit-oriented (as opposed to midlayer-oriented) would address our use-case better.</p> <p>So, I set out to design us a bespoke task queueing system for our Go daemons. Some of the goals were:</p> <ul> <li>Ability to manage work in Goroutines instead of separate daemons<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></li> <li>Easy handling of re-attempts with an exponential backoff</li> <li>Graceful termination (stop accepting new tasks and flush the queue)</li> <li>Observability with <a href="https://prometheus.io/">Prometheus</a></li> </ul> <p>The solution came in the form of our new <a href="https://sr.ht/~sircmpwn/dowork/">&ldquo;dowork&rdquo;</a> Go library. Here&rsquo;s the basic usage:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="s">&#34;git.sr.ht/~sircmpwn/dowork&#34;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">queue</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">work</span><span class="p">.</span><span class="nf">NewQueue</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">queue</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">())</span><span class="w"> </span><span class="c1">// Does not block</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">queue</span><span class="p">.</span><span class="nf">Submit</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// Do work...</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">})</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">queue</span><span class="p">.</span><span class="nf">Shutdown</span><span class="p">()</span><span class="w"> </span><span class="c1">// Blocks until all pending tasks are complete</span><span class="w"> </span></span></span></code></pre></div><p>If you want to handle retries, create and enqueue your task in two steps:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">task</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">work</span><span class="p">.</span><span class="nf">NewTask</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// Do work...</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}).</span><span class="nf">Retries</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">queue</span><span class="p">.</span><span class="nf">Enqueue</span><span class="p">(</span><span class="nx">task</span><span class="p">)</span><span class="w"> </span></span></span></code></pre></div><p>This will automatically retry your task with an exponential backoff if it returns an error.</p> <p>Let&rsquo;s take a look at this in action! Consider our email handling module.</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Returns a task which will send this email for the work queue. If the caller</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// does not need to customize the task parameters, the Enqueue function may be</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// more desirable.</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">func</span><span class="w"> </span><span class="nf">NewTask</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="o">*</span><span class="nx">gomail</span><span class="p">.</span><span class="nx">Message</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="nx">work</span><span class="p">.</span><span class="nx">Task</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">conf</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">config</span><span class="p">.</span><span class="nf">ForContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">work</span><span class="p">.</span><span class="nf">NewTask</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nf">Send</span><span class="p">(</span><span class="nx">config</span><span class="p">.</span><span class="nf">Context</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="nx">conf</span><span class="p">),</span><span class="w"> </span><span class="nx">m</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}).</span><span class="nf">Retries</span><span class="p">(</span><span class="mi">10</span><span class="p">).</span><span class="nf">After</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span><span class="w"> </span><span class="nx">task</span><span class="w"> </span><span class="o">*</span><span class="nx">work</span><span class="p">.</span><span class="nx">Task</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">task</span><span class="p">.</span><span class="nf">Result</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;MAIL TO %s: &#39;%s&#39; sent after %d attempts&#34;</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">strings</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nf">GetHeader</span><span class="p">(</span><span class="s">&#34;To&#34;</span><span class="p">),</span><span class="w"> </span><span class="s">&#34;;&#34;</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">strings</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nf">GetHeader</span><span class="p">(</span><span class="s">&#34;Subject&#34;</span><span class="p">),</span><span class="w"> </span><span class="s">&#34;;&#34;</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">task</span><span class="p">.</span><span class="nf">Attempts</span><span class="p">())</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;MAIL TO %s: &#39;%s&#39; failed after %d attempts: %v&#34;</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">strings</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nf">GetHeader</span><span class="p">(</span><span class="s">&#34;To&#34;</span><span class="p">),</span><span class="w"> </span><span class="s">&#34;;&#34;</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">strings</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">m</span><span class="p">.</span><span class="nf">GetHeader</span><span class="p">(</span><span class="s">&#34;Subject&#34;</span><span class="p">),</span><span class="w"> </span><span class="s">&#34;;&#34;</span><span class="p">),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">task</span><span class="p">.</span><span class="nf">Attempts</span><span class="p">(),</span><span class="w"> </span><span class="nx">task</span><span class="p">.</span><span class="nf">Result</span><span class="p">())</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// Enqueues an email for sending with the default parameters.</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">func</span><span class="w"> </span><span class="nf">Enqueue</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="o">*</span><span class="nx">gomail</span><span class="p">.</span><span class="nx">Message</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nf">ForContext</span><span class="p">(</span><span class="nx">ctx</span><span class="p">).</span><span class="nf">Enqueue</span><span class="p">(</span><span class="nf">NewTask</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="nx">m</span><span class="p">))</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// Creates a new email processing queue.</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">func</span><span class="w"> </span><span class="nf">NewQueue</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="nx">work</span><span class="p">.</span><span class="nx">Queue</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">work</span><span class="p">.</span><span class="nf">NewQueue</span><span class="p">(</span><span class="s">&#34;email&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w"> </span></span></span></code></pre></div><p>Some code for <a href="https://git.sr.ht/~sircmpwn/core-go/tree/master/email/worker.go">handling contexts</a> is omitted for brevity. Here we use a closure to enclose the message to be sent, and some extra details like the config file (which includes our SMTP details). We configure it for up to 10 retries, and log the result after the task is complete. Sending an email with this is pretty straightforward:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">m</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">gomail</span><span class="p">.</span><span class="nf">NewMessage</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">m</span><span class="p">.</span><span class="nf">SetAddressHeader</span><span class="p">(</span><span class="s">&#34;From&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;[email protected]&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;Jane Doe&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">m</span><span class="p">.</span><span class="nf">SetAddressHeader</span><span class="p">(</span><span class="s">&#34;To&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;[email protected]&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;John Smith&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">m</span><span class="p">.</span><span class="nf">SetHeader</span><span class="p">(</span><span class="s">&#34;Subject&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;An email subject&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">m</span><span class="p">.</span><span class="nf">SetBody</span><span class="p">(</span><span class="s">&#34;text/plain&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;An email body&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">email</span><span class="p">.</span><span class="nf">Enqueue</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="nx">m</span><span class="p">)</span><span class="w"> </span><span class="c1">// Doesn&#39;t block!</span><span class="w"> </span></span></span></code></pre></div><p>The next interesting component comes when it&rsquo;s time to terminate the process. We want to do the following things:</p> <ol> <li>Stop accepting new connections and free up the HTTP port for the new daemon</li> <li>Finish servicing existing requests, up to a timeout</li> <li>Finish running any already-queued tasks</li> <li>Terminate the process</li> </ol> <p>So the process looks like this:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">mail</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">email</span><span class="p">.</span><span class="nf">NewQueue</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">mail</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">())</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">// ...</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">go</span><span class="w"> </span><span class="nx">qserver</span><span class="p">.</span><span class="nf">Serve</span><span class="p">(</span><span class="nx">qlistener</span><span class="p">)</span><span class="w"> </span><span class="c1">// Asynchronously start the main HTTP server</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">sig</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Signal</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">signal</span><span class="p">.</span><span class="nf">Notify</span><span class="p">(</span><span class="nx">sig</span><span class="p">,</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Interrupt</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="o">&lt;-</span><span class="nx">sig</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">signal</span><span class="p">.</span><span class="nf">Reset</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Interrupt</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;SIGINT caught, initiating warm shutdown&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;SIGINT again to terminate immediately and drop pending requests &amp; tasks&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Terminating server...&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="nx">cancel</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nf">WithDeadline</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">(),</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nf">Now</span><span class="p">().</span><span class="nf">Add</span><span class="p">(</span><span class="mi">30</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">))</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">qserver</span><span class="p">.</span><span class="nf">Shutdown</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nf">cancel</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Terminating work queues...&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">work</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">mail</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">qserver</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Terminating process.&#34;</span><span class="p">)</span><span class="w"> </span></span></span></code></pre></div><p>As a bonus for observability, we also set up a secondary HTTP server on a kernel-assigned TCP port, which we can use to monitor the shutdown process:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">mux</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">http</span><span class="p">.</span><span class="nx">ServeMux</span><span class="p">{}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">mux</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="s">&#34;/metrics&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">promhttp</span><span class="p">.</span><span class="nf">Handler</span><span class="p">())</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">pserver</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">http</span><span class="p">.</span><span class="nx">Server</span><span class="p">{</span><span class="nx">Handler</span><span class="p">:</span><span class="w"> </span><span class="nx">mux</span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">plistener</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">net</span><span class="p">.</span><span class="nf">Listen</span><span class="p">(</span><span class="s">&#34;tcp&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;:0&#34;</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Prometheus listening on :%d&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">plistener</span><span class="p">.</span><span class="nf">Addr</span><span class="p">().(</span><span class="o">*</span><span class="nx">net</span><span class="p">.</span><span class="nx">TCPAddr</span><span class="p">).</span><span class="nx">Port</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">go</span><span class="w"> </span><span class="nx">pserver</span><span class="p">.</span><span class="nf">Serve</span><span class="p">(</span><span class="nx">plistener</span><span class="p">)</span><span class="w"> </span></span></span></code></pre></div><p>I also added a little extra log during the shutdown process:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Progress available via Prometheus stats on port %d&#34;</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">plistener</span><span class="p">.</span><span class="nf">Addr</span><span class="p">().(</span><span class="o">*</span><span class="nx">net</span><span class="p">.</span><span class="nx">TCPAddr</span><span class="p">).</span><span class="nx">Port</span><span class="p">)</span><span class="w"> </span></span></span></code></pre></div><p>This is just to print the Prometheus port closer to the shutdown event in the logs, for easy reference. <code>curl http://[::1]:<strong>$port</strong>/metrics</code> will provide Prometheus metrics, including the queue drain progress for the sysadmin to monitor.</p> <p>That&rsquo;s it! Some future improvements along these lines will include:</p> <ul> <li>Rigging this up with OpenRC so that our service manager can oversee these kinds of restarts</li> <li>More sophisticated coordination between the old and new server processes to reduce the window during which connections might be dropped<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></li> <li>Dumping the queue state on the second SIGINT so that the admin can review and possibly re-queue some of the tasks later</li> <li>Moving the queue into a secondary process or a remote machine, through some kind of remote submission mechanism</li> <li>Applying this work further towards the upcoming builds.sr.ht work distribution overhaul</li> </ul> <p>Stay tuned.</p> <p><a href="https://sr.ht/~sircmpwn/dowork/">View the &ldquo;dowork&rdquo; project on SourceHut →</a></p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>Without necessarily making it difficult to move executors to separate processes or machines later on&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>Update 2020-10-07: We&rsquo;ve successfully tested using <a href="https://github.com/kavu/go_reuseport">SO_REUSEPORT</a> to allow the replacement daemon to start up before the defunct daemon starts shutting down, which completely eliminates the window during which connections could be dropped. We still need to work on coaxing OpenRC into handling this service lifecycle; we&rsquo;ll likely write a follow-up post about this.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> SourceHut API 2.0 dev log https://sourcehut.org/blog/2020-09-25-api-2-updates/ Fri, 25 Sep 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-09-25-api-2-updates/ <p>Completing the project now known as &ldquo;API 2.0&rdquo; is one of the most important steps in finalizing the <a href="https://sourcehut.org/alpha-details">sr.ht beta</a>, and I&rsquo;ve been trying to keep the community abreast of developments, especially on the <a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev">sr.ht-dev</a> mailing list. I&rsquo;m summarizing for the blog as well today, some of our recent developments in this respect and planned work to come.</p> <details> <summary>Read more: why is API 2.0 is important to the beta?</summary> <p> SourceHut is a distributed system of "mini-services", each fulfilling its role in a particular domain &mdash; git.sr.ht handles git, builds.sr.ht handles CI, lists.sr.ht handles mailing lists, and so on. In order for these services to communicate effectively, good API design is critical. A good API is also necessary for SourceHut users to extend sr.ht with their own tools. <p> The legacy API was designed within the context of our Flask applications for the purpose of quickly meeting these needs during the design &amp; development of the sr.ht alpha. It's... not great. The RESTful design implies a tree-like structure, which does not map as well onto our data model &mdash; the "graph" of GraphQL does much better in this regard. Additionally, the implementation is somewhat inconsistent and leaves a lot to be desired in terms of robustness. The stronger type system of GraphQL enforces a baseline of consistency which, while achievable with the legacy approach, is much easier with the 2.0 approach. <p> The API design is an essential participant in proving the architecture design of sr.ht. In order to meet the confidence level we need to start the beta, we need a greater degree of confidence than the legacy approach offered. API 2.0 meets this requirement. Additionally, stability is going to be important post-beta: this is our last opportunity to make a clean break with the legacy API and ship a better, more stable design into production which we can comfortably support for longer. </details> <h2 id="progress-updates">Progress updates</h2> <p>Some of the progress which has been completed recently includes:</p> <h3 id="oauth-20-support">OAuth 2.0 support</h3> <p>The new meta.sr.ht API supports OAuth 2.0 for authentication. We previously advertised &ldquo;OAuth&rdquo; support, but the new implementation is actually conformant with <a href="https://tools.ietf.org/html/rfc6749">the RFC</a>. A draft of our OAuth 2.0 documentation can be read <a href="https://man.sr.ht/meta.sr.ht/oauth.md">here</a>.</p> <p>The design makes meta.sr.ht-api the source of truth for all things OAuth, and the meta.sr.ht-web (Python) frontend just issues GraphQL queries to manage it. meta.sr.ht-api is responsible for issuing personal access tokens, authorization tokens, and access tokens, and possibly refresh tokens in the future.</p> <p>The relevant GraphQL resolvers are <code>@internal</code>, so meta.sr.ht-web is the only client which is allowed to use them. However, this is a good proof-of-concept for later work which will expand this design to other resolvers, which third-party clients <em>are</em> permitted to use, to relocate more sources of truth from -web into -api. The ultimate intention is to remove SQLAlchemy from the -web services entirely and just have them execute GraphQL queries to fetch the necessary information to present the web UI.</p> <p>The access tokens themselves (both personal access tokens and bearer tokens) take the form of a <a href="https://baremessages.org">BARE</a>-encoded payload specifying the username, client ID, authorized scopes, and token expiration, authorized with HMAC, and base64 encoded. Resolvers which can be accessed with these tokens, and the required scopes to access them, are controlled by the new <code>@access</code> directive in the GraphQL schema.</p> <p>To revoke a token, its SHA is computed and a revocation entry is added to Redis. Additionally, the token record in the database has its expiration set to the current time. When token authorization is checked, its hash is computed and the revocation status is quickly queried from Redis. In general, Redis is treated as an ephemeral cache on sr.ht — in the event that the data is lost, a new revocation list can be constructed by simply querying the database for expired tokens and issuing new revocations for them.</p> <p>These changes brings the total number of authorization methods up to four:</p> <ol> <li><code>@internal</code> authentication, based on a single-use token encrypted with SourceHut internal private keys, and used for service-to-service authorization. It has access to resolvers which are not normally available to the public.</li> <li>OAuth 2.0 authentication, via either bearer tokens or personal access tokens, which are limited by the scopes laid down on each resolver with <code>@access</code>.</li> <li>SourceHut web login cookie authorization, intended for use with the <a href="https://meta.sr.ht/graphql">web-based GraphQL playgrounds</a>, which have an access level equivalent to personal access tokens.</li> <li>Legacy OAuth tokens, which must have <code>*</code> permissions, and are only granted read-only access.</li> </ol> <p>The fourth method, legacy OAuth tokens, is planned to be hastily removed. In order to facilitate this, I intend to start recording when a legacy token is used to access the GraphQL API. This information will be used to create a list of users who would be affected by the removal of this feature; they&rsquo;ll be sent an email with another 30 days of notice (and instructions on switching to API 2.0 tokens) before it&rsquo;s removed.</p> <p>A side note: the new personal access token design allows you to create personal access tokens with limited scopes, and removes the ability for third-parties to create bearer tokens with unlimited account access.</p> <p>These systems are security-critical, so some eyes on the code from the community would be appreciated. The bulk of the code can be reviewed in the <code>writable-api</code> branch of <a href="https://git.sr.ht/~sircmpwn/meta.sr.ht/tree/writable-api">meta.sr.ht</a>, and at the tip of <a href="https://git.sr.ht/~sircmpwn/gql.sr.ht">gql.sr.ht</a>.</p> <h3 id="database-abstraction">Database abstraction</h3> <p>SQLAlchemy has been a major pain point for the web applications, and the database abstraction to be used with GraphQL has been carefully designed to avoid the same pitfalls. Specifically, it has been made as thin as possible. The abstraction is now <em>mostly</em> done, as support was recently added for GraphQL mutations. The only outstanding improvement might be to introduce better support code for cursors, which are used to access lists of things (e.g. PGP keys for an account).</p> <p>Another place where there might be improvement is in reducing the number of total round-trips. It would be feasible to defer loading detailed user information until it&rsquo;s actually necessary, for example, and also possible to cache some basic relationships (e.g. username to user ID) in memory, though such a cache would only affect corner cases. Additionally, if we can update the mutation support code to use PostgreSQL&rsquo;s <code>RETURNING</code> feature, we can avoid a round-trip to fetch the record we intend to mutate. This may require forking <a href="https://github.com/Masterminds/squirrel">squirrel</a>. In theory, it should be possible to reduce the number of round-trips for any given request to be equal to the number of distinct resource types it implicates. Further consolidation may be possible with more elaborate queries in the future.</p> <h3 id="initial-performance-testing">Initial performance testing</h3> <p>Initial performance tests on routine read-only queries suggests that we can expect to handle 1,000 reqs/sec/thread with a target service time of 20ms per request. Write queries are about half as efficient, and we could expect perhaps 100 reqs/sec/thread at 200ms each. The bottleneck on write queries seems to be in PostgreSQL, rather than in our code. More research will be necessary if it becomes an issue. In order to scale up parallelism, we&rsquo;ll have to plan out the number of connections per PSQL server; I expect that we have plenty of room with our current deployment to tune this upwards.</p> <p>For scaling in the future, read-only queries can be distributed over horizontally scalable PSQL secondaries. The API code is already set up to use read-only transactions when appropriate, so redirecting these should be easy. Write access will still have to be limited to a single master server, which will need to scale vertically. If this becomes a bottleneck in the future, we may research sharding options. However, writes are much less common than reads, and if we direct the read load off of the master server we should be able to scale quite far without much cost.</p> <p>Some initial testing with pgbouncer raised some issues with feature compatibility between pgbouncer, the PSQL write protocol, lib/pq, and psycopg2. We plan on using pgbouncer more to meet availability requirements than scalability requirements, however, so an in-depth answer to these issues will be explored separately.</p> <h2 id="future-work">Future work</h2> <p>Some things which are next up in the pipeline:</p> <h3 id="async-dispatch">Async dispatch</h3> <p>The next major problem which needs to be addressed is the handling of asynchronous work in the GraphQL backends. Some tasks will need to be done async, including webhook and email delivery. Additionally, a lightweight means of firing off small tasks to be completed async whenever needful would be helpful to have, for small optimizations which move more logic out of codepaths which would block delivering responses to clients.</p> <p>To this end, I intend to build a general-use system for handling queuing, executing, and re-attempting async tasks in Go applications. This will be able to live in any Go process, and my expectation is that some of them will live inside of the GraphQL backends themselves, and some will live in dedicated daemons which will have work assigned to them by the GraphQL backends remotely. Whether or not a task will be handled in- or out-process is a function of the tasks predicted reliability and importance, and thus the need for external management of that task queue.</p> <p>For example, email delivery is likely to be handled in-process. We deliver mail through a dedicated mail server, which has its own queuing and re-delivery mechanisms built-in. Mail delivery is likely to succeed, and relatively soon after it enters our task queue. The in-process queues are unlikely to get very full. Webhook delivery, on the other hand, is important for preserving a consistent data model across our services, and does not have a secondary queue or redelivery mechanism like email. Therefore, managing it through a separate daemon would be ideal. However, both of these can use the same code - the only difference would be where the tasks come from, be it somewhere up the call stack or a remote request.</p> <p>Some things that this code will need to support are:</p> <ul> <li>Warm process shutdown (including shutting down the HTTP listener in the GraphQL backends to free up the port for the next daemon, or to stop accepting new tasks in the remote daemons)</li> <li>Queueing, executing, and re-delivery of tasks, with exponential backoff</li> <li>Observability via Prometheus (and the relevant alarms)</li> <li>The ability to serialize state to disk</li> </ul> <p>This design will likely have implications for the upcoming builds.sr.ht work distribution overhaul as well.</p> <h3 id="graphql-native-webhooks">GraphQL-native webhooks</h3> <p>To continue supporting legacy webhooks, we will first need to build an implementation of the legacy system for the GraphQL backends. Naturally, this is blocked by the async solution above, but it should provide a good proving grounds for that work.</p> <p>We have some basic sketches for handling webhook registration and delivery with GraphQL, but a proof-of-concept needs to be built. The basic idea is that, when registering a new webhook, you provide a GraphQL query which we execute before delivering your webhook and use as the request payload for the webhook. This can be used to eliminate any further API requests your webhook endpoint might have to perform to gather any additional information it needs to complete its work.</p> <p>A plan will need to be made for transitioning our existing code from legacy webhooks to API 2.0 webhooks.</p> <h3 id="packaging">Packaging</h3> <p>We&rsquo;ll need to change how we handle the distribution packages to support these updates. It&rsquo;s likely that, for example, the &ldquo;meta.sr.ht&rdquo; package will become a meta-package which depends jointly on meta.sr.ht-web (where the Python web application will be re-homed to), meta.sr.ht-api (the GraphQL backend), and perhaps meta.sr.ht-async. If we grow any additional frontends in the future (Gemini, for instance), this will make it easy to add them. It will also make it easy to offer GraphQL APIs without the web application, should any third-party installations desire this.</p> <h3 id="other-future-work">Other future work</h3> <ul> <li>gql.sr.ht is going to be merged into core-go soon.</li> <li>A lot of refactoring has gone into the GQL support code in the course of developing OAuth 2.0 and the database abstraction for meta.sr.ht; git.sr.ht&rsquo;s GraphQL proof-of-concept will have to be updated to follow these changes.</li> <li>A transition plan for deprecating the legacy API entirely will have to be prepared prior to finalizing the beta.</li> </ul> <p>Please make your way to <a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev">sr.ht-dev</a> to keep up with and participate in the discussion.</p> What's cooking on Sourcehut? September 2020 https://sourcehut.org/blog/2020-09-15-whats-cooking-september-2020/ Tue, 15 Sep 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-09-15-whats-cooking-september-2020/ <p>SourceHut development continues its constant march through the alpha this month, and I&rsquo;m here to tell you all about it. Our users now number 17,194, thanks to 511 new members joining us since the last update. To our new users: welcome! And to our older members: thanks for being here! I hope everyone new finds a warm welcome in the rest of the community.</p> <p>Earlier this month, I held a public meeting to discuss the plans for the beta, and we felt that it was a pretty good way to connect with the community. Going forward, the day following each status update (so, tomorrow), I&rsquo;m going to hold a public meeting where you&rsquo;re welcome to join up and ask any questions or provide any feedback. In turn, I&rsquo;ll have questions of my own for the community, and will be looking forward to hearing your thoughts.</p> <p>The next meeting will be held tomorrow, September 16th, at 15:00 UTC, on Mumble. We&rsquo;ll be meeting in the SourceHut room on the voice.mnus.de server, on port 64738. Please join us!</p> <p>And following that earlier meeting, I&rsquo;d like to share with you the thoughts on the beta progress. The path towards completing the alpha is quite clear now, and as such, I&rsquo;ve updated all of the <a href="https://todo.sr.ht/trackers/~sircmpwn?search=sr.ht">bug trackers</a> to include a &ldquo;beta&rdquo; label, and marked all of the tickets which block the completion of the alpha as such. The big-ticket blockers are:</p> <ul> <li>Finalize pricing (a survey will be sent out - can you recommend some software for this?) and billing system overhaul</li> <li>GraphQL APIs</li> <li>Work distribution overhaul for builds.sr.ht</li> <li>Web-based code review for lists.sr.ht</li> <li>More hub.sr.ht cross-service integrations</li> </ul> <p>Next month marks the end of the second year of the alpha, and I&rsquo;ll prepare an extended status update which goes into detail on what remains and how we&rsquo;re going to complete the beta.</p> <h2 id="general-improvements">General improvements</h2> <p>Headers in Markdown across sourcehut now include a link to that header which appears on hover, which should be useful for linking to a specific header anywhere on the services. Thanks to gildarts for adding that!</p> <p>Admins of third-party instances will also be pleased at some recent improvements, including better exception emails and user administration screens, as well as fixes for long put-off exceptions in various edge cases throughout and improvements to the soundness of the database schema.</p> <h2 id="project-hub">Project hub</h2> <p>Project #tags are now supported on the project hub, with the goal of making it easier to discover projects and for communities to establish themselves around a topic. This was only added a few days ago, so most projects don&rsquo;t have tags yet — please take a moment to add some for your projects if you can! Thanks to наб again for implementing this feature.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>meta.sr.ht is the primary focus for the GraphQL expansion, and work is underway adding a new OAuth 2.0-compliant authorization process and introducing writable GraphQL API access. See the writable-api branch if you&rsquo;re curious.</p> <p>Some user-facing improvements have also been made this month, such as support for TOTP recovery codes. Disable and re-enable TOTP on your account to generate these. Additionally, I&rsquo;ve added security emails which are sent to you whenever anything security-relevant occurs on your account, such as a password change or new SSH key.</p> <p>наб also added a feature which allows new users to enter their PGP key during the registration process, so that the registration email is encrypted when sent. This makes it possible to never receive any unencrypted emails from sr.ht.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>наб has introduced many improvements to git.sr.ht this month, including a blame view, path-specific logs, and two features for push options: updating the repo description or visibility, and submitting arbitrary build manifests other than <code>.build.yml</code> or <code>.builds/*.yml</code>. <a href="https://man.sr.ht/git.sr.ht/#push-options">Docs here</a>. Thanks наб!</p> <h2 id="todosrht">todo.sr.ht</h2> <p>You can now edit comments on tickets.</p> <h2 id="mansrht">man.sr.ht</h2> <p>Adding a sorely overdue feature, gildarts implemented a user index page for man.sr.ht, where you can list the wikis on your account. Thanks gildarts!</p> SourceHut's PeerTube bootstrap fund: first batch https://sourcehut.org/blog/2020-09-09-peertube-first-batch/ Wed, 09 Sep 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-09-09-peertube-first-batch/ <p>In May we announced our initiative to <a href="https://sourcehut.org/blog/2020-05-15-peertube-bootstrap-fund/">fund video creators who wanted to get started on PeerTube</a>. <a href="https://joinpeertube.org/en/">PeerTube</a> is a free software project which creates a federated network of video sharing platforms, each of which owned and operated by independent, small groups of creators or users or both. This decentralized, democratized approach to video publishing, on an open source platform, is compelling to us, and we wanted to help bootstrap it with new content for users to enjoy on the platform.</p> <p>Today we&rsquo;re happy to announce that we&rsquo;ve selected our first two video creators to receive funding and equipment: Matthew Bryant and Tom Cooks. We&rsquo;ve brought these creators on board with our PeerTube instance at <a href="https://spacepub.space">spacepub.space</a>, which aims to be a private instance focused on video publishers. It&rsquo;s federated with <a href="https://joinpeertube.org/en/instances">many other PeerTube instances</a> which would be happy to have your user account, from where you can subscribe to enjoy these videos — or you can subscribe with each channel&rsquo;s RSS feed.</p> <hr> <p>Let&rsquo;s introduce our first two creators:</p> <p>Matthew is an FPGA (field programmable gate array) enthusiast who is making use of the <a href="https://github.com/3b1b/manim">manim</a> open-source framework for educational video creation designed and made famous by YouTube channel 3blue1brown. Matthew&rsquo;s channel will become a great resource on learning about FPGA&rsquo;s from the ground up to the expert level.</p> <iframe width="560" height="315" sandbox="allow-same-origin allow-scripts allow-popups" src="https://spacepub.space/videos/embed/d3a1b58f-6560-47b6-b183-53dd572a6fde" frameborder="0" allowfullscreen></iframe> <p><a href="https://spacepub.space/video-channels/mbryant_channel/videos">Subscribe to Matthew&rsquo;s channel ➔</a></p> <p>Tom is a passionate cook who wants to use the platform to share videos teaching viewers how to cook traditional meals with cheap and accessible ingredients. Check out his first video on flatbread here:</p> <iframe width="560" height="315" sandbox="allow-same-origin allow-scripts allow-popups" src="https://spacepub.space/videos/embed/0656038d-7255-411b-beff-2d652e71d804" frameborder="0" allowfullscreen></iframe> <p><a href="https://spacepub.space/video-channels/tom_cooks/videos">Subscribe to Tom&rsquo;s channel ➔</a></p> <hr> <p>We&rsquo;re working with a third creator as well (or creators — it&rsquo;s a two-person team), who should have their first video prepared in the foreseeable future. We&rsquo;re planning to start accepting applications for the second batch of creators soon; keep an eye on this blog for updates. Enjoy the videos, and subscribe to these creators!</p> SourceHut contributor spotlight https://sourcehut.org/blog/2020-08-26-contributor-spotlight/ Wed, 26 Aug 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-08-26-contributor-spotlight/ <p>SourceHut is 100% free and open source software, and we accept contributions from any of our users. Dozens of your peers have contributed improvements to the services! I wanted to share a &ldquo;thank you&rdquo; with everyone who&rsquo;s helped out, and draw attention to some of my favorite contributions.</p> <p>From feature development, to bug fixes, to third-party packaging, to operations improvements and more, external contributors have left their impact in all facets of the software. Tools sr.ht users rely on every day were implemented by their peers, and the reliability and performance of the service has been guaranteed thanks in no small part to their hard work.</p> <h1 id="ivan-habuneks-improvements-todosrht">Ivan Habunek&rsquo;s improvements todo.sr.ht</h1> <p>First, I&rsquo;d like to give a shoutout to Ivan, who has the longest history of consistent high-quality contributions to the project, dating to the pre-alpha phase. We can thank Ivan for a lot of todo.sr.ht features, including:</p> <ul> <li>Ticket labels</li> <li>Ticket assignees</li> <li>Mentioning &amp; linking to users and other tickets</li> <li>Improved search on todo.sr.ht and across the services</li> </ul> <p>Ivan is also one of the &ldquo;bus factor&rdquo; delegates, and has access to production todo.sr.ht systems in order to mitigate the risk a single point of failure. Thank you for all of your help, Ivan!</p> <h1 id="набs-improvements-to-everything">наб&rsquo;s improvements to everything</h1> <p>наб is a recent contributor to SourceHut, but over the past month she has become <a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev/patches?search=from%3A~nabijaczleweli">extremely prolific</a>, submitting 73 patches and counting. In fact, that very link showing all of наб&rsquo;s patches relies on a search feature submitted by none other than наб herself. Some other nice improvements include:</p> <ul> <li>Blame and per-file log views on git.sr.ht</li> <li>Default branches other than &ldquo;master&rdquo; on git.sr.ht</li> <li>README files in markup languages other than Markdown on hg, git, and hub</li> </ul> <p>Not to mention dozens of bugfixes, refactorings, refinements, and small improvements implemented for <strong>every</strong> sr.ht service. Thanks a lot, наб!</p> <h1 id="distribution-packagers-eli-and-denis">Distribution packagers Eli and Denis</h1> <p>sr.ht upstream runs on Alpine Linux, and we maintain an Alpine <a href="https://mirror.sr.ht/alpine/">package repository</a> for this purpose, and encourage third party installations to utilize it. However, thanks to the hard work of Eli Schwartz and Denis Laxalde, there are <a href="https://man.sr.ht/packages.md">official Arch Linux and Debian repositories</a> available as well. These are automatically kept up-to-date in stride with our upstream developments through some integrations with builds.sr.ht, all of which is maintained by volunteers. Thanks for your hard work, fellas!</p> <h1 id="build-image-maintainers">Build image maintainers</h1> <p>builds.sr.ht supports <a href="https://man.sr.ht/builds.sr.ht/compatibility.md">a large variety of build images</a>, from Ubuntu to Debian, Arch Linux to NixOS, FreeBSD and OpenBSD, and even Plan 9. Maintaining these is a lot of work and requires expertise with the system in question - and for most of the images, this expertise and maintenance is provided by community volunteers. Big thanks to Timothée Floure, Simon Ser, Francesco Gazzetta, and Jarkko Oranen for working hard to make sure that their platforms are well-represented on SourceHut.</p> <h1 id="operations-contributors-phillip-and-ignas">Operations contributors Phillip and Ignas</h1> <p>Our monitoring software is <a href="https://metrics.sr.ht/graph">available to the public</a>, and we keep our alarms in a <a href="https://git.sr.ht/~sircmpwn/metrics.sr.ht">git repository</a>. You&rsquo;d think that our internal service monitoring would be an unlikely candidate for third-party contributions, but Phillip Riegger and Ignas Kiela both took it upon themselves to contribute improvements to our monitoring system. In fact, after sr.ht&rsquo;s <a href="https://status.sr.ht/issues/2020-06-28-unplanned-git.sr.ht-outage/">only unplanned outage in 2020</a>, Ignas was the one who wrote the patch adding an alarm which would have caught the problem earlier. Thanks for your help, both of you!</p> <h1 id="improvements-to-the-broader-foss-community">Improvements to the broader FOSS community</h1> <p>SourceHut users, contributors, and developers have collectively made a great habit of reaching out to the rest of the FOSS ecosystem, writing patches and getting improvements merged which helps tie together the whole ecosystem into a more robust and cohesive whole. SourceHut users have driven improvements to git &amp; Mercurial, pygit2 &amp; libgit2, Go, Rust, and Python, emacs, vim, and VSCode, a half-dozen Linux distributions, FreeBSD and OpenBSD, and even competing services including GitHub, GitLab, Gitea, and Pagure, and dozens more projects still. I hope we will continue to boldly go forth and enrich the broader community!</p> <h1 id="and-all-the-little-ones">And all the little ones&hellip;</h1> <p>There are dozens more contributors who didn&rsquo;t make the article. There&rsquo;s a consistent trickle of one- or two-off contributions, fixing small bugs, improving docs, and scratching itches. I&rsquo;m grateful for these as well! Thank you to everyone who contributes. Large or small, your hard work is appreciated.</p> What's cooking on Sourcehut? August 2020 https://sourcehut.org/blog/2020-08-16-whats-cooking-august-2020/ Sun, 16 Aug 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-08-16-whats-cooking-august-2020/ <p>Another month passes and we find ourselves writing (or reading) this status update on a quiet, rainy Sunday morning. Today our userbase numbers 16,683 members strong, up 580 from last month. Please extend a kind welcome to our new colleagues! Thanks for reading these posts and keeping up with what&rsquo;s new on the platform.</p> <p>First, I&rsquo;d like to extend a thanks to contributor наб, who has been sending an <a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev?search=from%3Anabijaczleweli">impressive number</a> of patches lately, and is responsible for most of the features detailed in this update. Other contributors who deserve thanks this month include 2xsaiko, Amin Bandali, Chris Vittal, gildarts, and Peter Sanchez. Thanks, everyone!</p> <p>For my part, I&rsquo;ve been focused on operational work this month. I oversaw the installation of and migration to the new hg.sr.ht server, which should enjoy improved performance and support a larger number of repositories going forward. The same server is also going to be useful as a testbed for our new standard VM server setup, which will scale better to long-term high-availability plans. Additionally, our PostgreSQL robustness deployment has been overhauled, which should lend improvements both to integrity and availability.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>git.sr.ht now supports default branches other than master. For details on changing your default branch name, <a href="https://man.sr.ht/git.sr.ht/#changing-the-default-branch">consult the docs</a>.</p> <p>Many additional minor bug fixes and performance improvements have been made throughout. For example, non-UTF-8 branch &amp; tag names are handled better now, with additional improvements heading to pygit2 upstream.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>The Ubuntu images have been overhauled to more closely map to the upstream release schedule. <a href="https://man.sr.ht/builds.sr.ht/compatibility.md">Consult the compatibility page</a> for details. Affected users were emailed before the update rolled out; if you did not receive an email then it is unlikely that you will have to change your build manifests.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>A number of improvements have been made for logged-out/anonymous users, mostly minor changes. One larger change is that users without accounts may now subscribe to specific tickets by email.</p> <h2 id="listssrht">lists.sr.ht</h2> <p>Searching by username is now supported in the From, To, and Cc fields, via the <code>from:~username</code> search key format. Additionally, git patches prepared with <code>git send-email --rfc</code> are now correctly recognized as such.</p> <h2 id="project-hub">project hub</h2> <p>When the hub submits CI jobs to builds.sr.ht for patches in mailing lists, a builds.sr.ht job group is now utilized. This reduces the number of emails sent in response to one, even for repos with many build manifests.</p> <p>Additionally, a number of small improvements have been made to increase the visibility of featured projects.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>For users who run their own instance of meta.sr.ht, PAM support has been added for authentication, allowing you to use the Unix account database for usernames and passwords rather than storing them in SQL.</p> Sourcehut Q2 2020 Financial report https://sourcehut.org/blog/2020-07-17-sourcehut-q2-2020-financial-report/ Fri, 17 Jul 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-07-17-sourcehut-q2-2020-financial-report/ <p>In summary, SourceHut is financially healthy. Our revenue continues to grow and we are profitable and becoming more so. We have also been able to re-invest some of our profits into the broader free software and free culture community.</p> <small> Disclaimer: this report is a summarized approximation of our financials, and is not used for tax purposes. </small> <h2 id="revenue-sources">Revenue sources</h2> <p>Sourcehut receives revenue from paid user subscriptions. During Q1, we processed 1,855 invoices. The invoices paid break down as:</p> <pre><code>930 $2 (paid monthly) 433 $5 (paid monthly) 148 $10 (paid monthly) 246 $2 (paid yearly) 74 $5 (paid yearly) 24 $10 (paid yearly) </code></pre> <p>The total gross revenue during Q2 was $16,335, which after transaction fees is $15,204. This is basically identical to the revenue from Q1, however, the breakdown in revenue sources has changed. We saw growing subscriptions in almost every category — except for $10/year, which shrunk by 30%. This was unexpected, but we are not especially concerned, as it was made up for with growth in other areas and is unlikely to indicate a long-term trend. In any case, this is a 289% increase from Q2 2019, which <em>does</em> continue to support a trend of strong YoY growth.</p> <p>In Q2 2,551 users registered for an account, of which 302 have paid (11.8%). This matches closely with our overall conversion rate of 11.7% (1,888 of 16,140 users at the time of writing). As of July 2020, the breakdown in subscription levels is the following:</p> <pre><code>342 $2 (paid monthly) 156 $5 (paid monthly) 53 $10 (paid monthly) 916 $2 (paid yearly) 307 $5 (paid yearly) 114 $10 (paid yearly) </code></pre> <p>The monthly revenue from these subscriptions (with annual payments amortized) is approximately $5,544 after transaction fees, an increase in $895 over Q1. This is consistent with our historical rate of growth.</p> <p>At the end of Q2, SourceHut had $17,383 in the bank.</p> <h2 id="expenses">Expenses</h2> <p>Breakdown of Q2 expenses:</p> <pre><code>$5000 Set aside for PeerTube initiative $1950 Philadelphia datacenter lease (inc. network, power, etc) €1000 Donation to Framasoft $1253 Misc. server equipment $600 LWN advertisement $300 GitHub sponsorship of pygit2 $80 Domain name registrations and renewals </code></pre> <p>Our expenses were unusually high during this period, as we decided to re-invest in the community in several respects. The <a href="https://sourcehut.org/blog/2020-05-15-peertube-bootstrap-fund/">PeerTube bootstrap fund</a> is a clear outlier, and we also donated to the PeerTube developers. Additionally, we&rsquo;ve set up a recurring donation with the maintainer of pygit2, an important library that we depend on to provide git.sr.ht service. We may be interested in sponsorships for other projects in our dependency tree; please reach out if you are interested.</p> <p>As an experiment, we also spent $600 on an LWN advertisement campaign during this quarter. The following advertisement was shown on LWN.net:</p> <p><img src="https://l.sr.ht/E3-r.png" alt="An advertisement which reads as follows: &ldquo;sourcehut.org: git &amp; hg repos, mailing lists, fast CI for Linux &amp; BSD; no JavaScript required; 100% free software. Paid Advertisement&rdquo;"></p> <p>We received 50,000 impressions and 113 click-throughs (0.22%). This is considered fairly typical for this kind of advertisement. The results were not strong enough to consider a second campaign for the time being; our other marketing approaches are more effective.</p> <p>In Q3, we plan on spending around $4K-$5K on the installation of a new server to handle hg.sr.ht growth, as well as filling a few other roles, mainly for high availability. Otherwise we have no unusual expenses planned.</p> What's cooking on Sourcehut? July 2020 https://sourcehut.org/blog/2020-07-15-whats-cooking-july-2020/ Wed, 15 Jul 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-07-15-whats-cooking-july-2020/ <p>As the unfeeling hand of time drags us relentlessly through its cold maw, we occasionally spend some of our precious moments writing (or in your case, reading), monthly status updates on the progress of the SourceHut alpha. Today is such a day - welcome back! Our audience has grown by 645 members this month, bringing our total userbase to 16,103. Please give a hearty welcome to our new peers!</p> <h2 id="general-news">General news</h2> <p>A short outage for hg.sr.ht is planned to take place sometime in the next few weeks, as we migrate to a new box. <a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev/%3CC46HQADCD895.383VE5JFF0N24%40homura%3E">The plan is outlined on sr.ht-dev</a>, and we expect to experience anywhere from 5 to 30 minutes where hg.sr.ht is read-only. The final dates will be posted on <a href="https://status.sr.ht">status.sr.ht</a> and announced on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-announce">sr.ht-announce</a> when the plan is finalized.</p> <p>We have also migrated all services to a new markdown engine based on <a href="https://github.com/miyuchina/mistletoe">Mistletoe</a>. If you encounter any strange Markdown-related problems, please <a href="https://todo.sr.ht/~sircmpwn/sr.ht">file a ticket</a> and mention ~araspik. Thank you for taking on this work, ~araspik! It took several months of effort to carefully test everything.</p> <p>I have also completed a lot of system operations work in this past month. We have <a href="https://man.sr.ht/ops/robust-psql.md">planned out improvements to our PostgreSQL strategy</a>, which will enable us to have real-time backups and failover capability. This is mostly useful for limiting downtime during planned maintanenace, but is also useful for the long-term goal of high availability.</p> <h2 id="listssrht">lists.sr.ht</h2> <p>The most exciting development in this round of updates is likely to be the integration between lists.sr.ht and builds.sr.ht to bring continuous integration to mailing lists on SourceHut. You may have seen the announcement on the blog yesterday — give it a read. The tl;dr is that if you <a href="https://sr.ht/projects/create">create a project</a> on the project hub, and add a mailing list and git repositories, it&rsquo;ll automatically submit any patches sent to your mailing list using the <code>.build.yml</code> (or <code>.build/*.yml</code>) from the repository. The subject prefix (for example, &ldquo;[PATCH my-project]&rdquo;) is used to identify the git repository that the patch is intended for (in this case, &ldquo;my-project&rdquo;).</p> <p><a href="https://lists.sr.ht/~emersion/mrsh-dev/patches/11599"><img src="https://l.sr.ht/Z328.png" alt="A screenshot of build status indicators for a patchset on lists.sr.ht"></a></p> <p>Additionally, at the request of Elias Naur, I have added a button to each patchset and thread in the mailing list archives which will forward the whole thread to you, so you can reply and comment on patches from the comfort of your inbox even if you were not subscribed to the mailing list at the time.</p> <p>Finally, mailing list deletion has been implemented at long last.</p> <h2 id="project-hub">Project hub</h2> <p>Following the addition of mailing list deletion to lists.sr.ht, the project hub was updated to support removing mailing lists and, if you so desire, deleting entire projects.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Routine build image updates:</p> <ul> <li>NixOS images have received robustness updates (thanks Francesco Gazzetta!)</li> <li>Ubuntu 18.10 and 19.04 has been removed, following their deprecation upstream</li> <li>Ubuntu 20.10 (Groovy) has been added as ubuntu/next</li> <li>Alpine 3.8 has been removed, following its deprecation upstream</li> <li>FreeBSD 11.x has been upgraded to FreeBSD 11.4</li> </ul> SourceHut adds continuous integration for mailing lists https://sourcehut.org/blog/2020-07-14-setting-up-ci-for-mailing-lists/ Tue, 14 Jul 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-07-14-setting-up-ci-for-mailing-lists/ <p>SourceHut offers a continuous integration platform called <a href="https://man.sr.ht/builds.sr.ht">builds.sr.ht</a>, which will boot up a virtual machine from any of <a href="https://man.sr.ht/builds.sr.ht/compatibility.md">nine operating systems</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, including various Linux, BSD, and Plan 9 distributions, using KVM, then clone your source code repository (or repositories) and run user-defined tasks to validate the code, automate deployment, run linters, and so on. A simple example manifest from <a href="https://sr.ht/~sircmpwn/scdoc">one of my projects</a> is the following:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">alpine/edge</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sources</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">https://git.sr.ht/~sircmpwn/scdoc</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">tasks</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">build</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd"> </span></span></span><span class="line"><span class="cl"><span class="sd"> cd scdoc </span></span></span><span class="line"><span class="cl"><span class="sd"> make</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">check</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd"> </span></span></span><span class="line"><span class="cl"><span class="sd"> cd scdoc </span></span></span><span class="line"><span class="cl"><span class="sd"> make check</span><span class="w"> </span></span></span></code></pre></div><p>For some time now, we&rsquo;ve automatically submitted these build manifests on your behalf when you push to your Git or Mercurial repository. To set this up for your repos, <a href="https://man.sr.ht/tutorials/getting-started-with-builds.md">consult the tutorial</a> and the <a href="https://man.sr.ht/builds.sr.ht">documentation</a>.</p> <p>SourceHut also famously endorses the email-driven workflow that git was designed for, with tools like <a href="https://git-send-email.io">git send-email</a>. This allows contributors to prepare patches locally, then email them to your project&rsquo;s mailing list. Now, after the introduction of the <a href="https://sourcehut.org/blog/2020-04-30-the-sourcehut-hub-is-live/">project hub</a>, we are well positioned to connect the disparate resources of your project — repositories, mailing lists, bug trackers, and so on — to bring out more functionality, and as of this week, that includes the automated testing of patches sent to your mailing lists.</p> <p><a href="https://lists.sr.ht/~emersion/mrsh-dev/patches/11599"><img src="https://l.sr.ht/Z328.png" alt="A screenshot of build status indicators for a patchset on lists.sr.ht"></a></p> <p>This is already working now for all projects on the project hub — to configure yours, just <a href="https://sr.ht/projects/create">create a project</a> and add both your source code repository and your mailing list to the project, and it&rsquo;ll take care of the rest automatically.</p> <p>There are some limitations, however:</p> <ul> <li> <p>Patches have to have their subject prefix configured to match the name of the repository being tested. For example, &ldquo;[PATCH example v2]&rdquo; will be matched to a repository named &ldquo;example&rdquo;. Senders can configure this like so:</p> <pre><code>git config format.subjectPrefix 'PATCH example' </code></pre> <p>This is done automatically for patches submitted using the git.sr.ht patchset preparation interface. We plan on improving this later by testing the patch for applicability against each of the repositories on your project.</p> </li> <li> <p><a href="https://todo.sr.ht/~sircmpwn/builds.sr.ht/52">Job groups</a> remain unimplemented on builds.sr.ht, which means that projects with many build manifests may see a lot of noise from the CI.</p> </li> <li> <p>Mercurial repositories are not yet supported.</p> </li> </ul> <p>Leveraging the project hub to connect your resources together is something which we intend to do in a few other domains as well. For example:</p> <ul> <li>Marking patchsets as integrated when they&rsquo;re applied upstream</li> <li>Linking git commits to tickets, and vice versa</li> <li>Adding the patch submitter to the build job access list so that they can SSH into failed VMs to diagnose the problem without the project admin&rsquo;s intervention</li> </ul> <p>And of course, this will play nicely into our plans of a more sophisticated maintainer-side workflow for handling patch submission on the web. Enjoy!</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>At the time of writing, at least. We&rsquo;re working on adding more.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> How we monitor our services https://sourcehut.org/blog/2020-07-03-how-we-monitor-our-services/ Fri, 03 Jul 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-07-03-how-we-monitor-our-services/ <p>Monitoring all of our services makes sure we&rsquo;re aware of problems when they occur, but most importantly, it helps us detect problems in advance — before they become outages. Our main tool for this task is <a href="https://prometheus.io">Prometheus</a>, an open source time-series database. It takes a snapshot of various metrics across all of our services every few seconds, then allows you to write queries which model trends in that data. Our instance is publicly available for you to explore at <a href="https://metrics.sr.ht">metrics.sr.ht</a>.</p> <p>The Prometheus docs have some good tips for <a href="https://prometheus.io/docs/prometheus/latest/querying/basics/">writing queries</a>. Here&rsquo;s an example:</p> <pre tabindex="0"><code>rate(node_cpu_seconds_total{mode=&#34;user&#34;,instance=&#34;node.git.sr.ht:80&#34;}[2m]) </code></pre><p>This returns a value between 0 and 1 which represents the current CPU usage across all nodes on git.sr.ht. You can check out <a href="https://metrics.sr.ht/graph?g0.range_input=1h&amp;g0.stacked=0&amp;g0.expr=rate(node_cpu_seconds_total%7Bmode%3D%22user%22%2Cinstance%3D%22node.git.sr.ht%3A80%22%7D%5B2m%5D)&amp;g0.tab=0">live graph here</a> (note that the live graph automatically selects the scale appropriate for the data — our server is probably not as overloaded as it looks here), or take a look at this graph I generated in advance (with the correct scale):</p> <p><img src="https://l.sr.ht/WOLU.svg" alt="An SVG showing CPU utilization on git.sr.ht"></p> <p>We can easily turn this into an alarm by rephrasing it as a boolean expression and writing a little bit of YAML:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl">- <span class="nt">alert</span><span class="p">:</span><span class="w"> </span><span class="l">High CPU usage</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">expr</span><span class="p">:</span><span class="w"> </span><span class="cp">&amp;cpu_gt_75pct</span><span class="w"> </span><span class="l">rate(node_cpu_seconds_total{mode=&#34;user&#34;}[2m]) &gt; 0.75</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">&lt;&lt; </span><span class="p">:</span><span class="w"> </span><span class="cp">&amp;brief</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">for</span><span class="p">:</span><span class="w"> </span><span class="l">5m</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">labels</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">severity</span><span class="p">:</span><span class="w"> </span><span class="l">interesting</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">annotations</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">summary</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Instance {{ $labels.instance }} is under high CPU usage&#34;</span><span class="w"> </span></span></span></code></pre></div><p>This is one of the few times where I take advantage of some of YAML&rsquo;s more advanced features: <code>&amp;cpu_gt_75pct</code> and <code>&amp;brief</code> are a kind of macro, which allows me to easily create derivative alarms, like these ones for network activity:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl">- <span class="nt">alert</span><span class="p">:</span><span class="w"> </span><span class="l">High network activity</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">expr</span><span class="p">:</span><span class="w"> </span><span class="cp">&amp;net_gt_10mibsec</span><span class="w"> </span><span class="p">&gt;</span><span class="sd"> </span></span></span><span class="line"><span class="cl"><span class="sd"> (rate(node_network_receive_bytes_total{device=~&#34;eth0|ens3|enp.*&#34;}[5m]) / 1024^2 </span></span></span><span class="line"><span class="cl"><span class="sd"> &gt; 10) or ( </span></span></span><span class="line"><span class="cl"><span class="sd"> rate(node_network_transmit_bytes_total{device=~&#34;eth0|ens3|enp.*&#34;}[5m]) / 1024^2 </span></span></span><span class="line"><span class="cl"><span class="sd"> &gt; 10)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">&lt;&lt; </span><span class="p">:</span><span class="w"> </span><span class="cp">*brief</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">annotations</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">summary</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Instance {{ $labels.instance }} &gt;10 MiB/s network use&#34;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">alert</span><span class="p">:</span><span class="w"> </span><span class="l">Sustained high network activity</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">expr</span><span class="p">:</span><span class="w"> </span><span class="cp">*net_gt_10mibsec</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">&lt;&lt; </span><span class="p">:</span><span class="w"> </span><span class="cp">*sustained</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">annotations</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">summary</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Instance {{ $labels.instance }} sustained &gt;10 MiB/s network use&#34;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">alert</span><span class="p">:</span><span class="w"> </span><span class="l">Prolonged high network activity</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">expr</span><span class="p">:</span><span class="w"> </span><span class="cp">*net_gt_10mibsec</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">&lt;&lt; </span><span class="p">:</span><span class="w"> </span><span class="cp">*prolonged</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">annotations</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">summary</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Instance {{ $labels.instance }} prolonged &gt;10 MiB/s network use&#34;</span><span class="w"> </span></span></span></code></pre></div><p>You can see all of our alarms online <a href="https://metrics.sr.ht/alerts">on metrics.sr.ht</a>, and you can see our YAML files in <a href="https://git.sr.ht/~sircmpwn/metrics.sr.ht">our git repository</a>. Some of our users have helpfully sent us patches to add new alarms and refine our existing ones - thanks folks! The advantages of being an open source business are numerous.</p> <p>When these alarms go off, they&rsquo;re routed into <a href="https://www.prometheus.io/docs/alerting/latest/alertmanager/">Alertmanager</a>. I found this particular part of the Prometheus stack a bit more annoying than the others, but eventually we rigged it up the way I like. We combine <a href="https://github.com/messagebird/sachet">sachet</a> with <a href="https://www.twilio.com/">Twilio</a> to route urgent alarms to my cell phone, and there I have some rules set up with <a href="https://llamalab.com/automate/">Automate</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> to make my phone go nuts when a matching SMS message arrives - it starts beeping and vibrating until I acknowledge the message.</p> <p>&ldquo;Urgent&rdquo; and &ldquo;important&rdquo; alarms are routed into our operational mailing list, <a href="https://lists.sr.ht/~sircmpwn/sr.ht-ops">sr.ht-ops</a>, which is also public. Browsing this list, you&rsquo;ll also see some automated emails which are not related to alarms — I&rsquo;ll get to these in a moment. We also have &ldquo;interesting&rdquo; alarms, which are routed to IRC, along with the urgent and important alarms, using <a href="https://github.com/google/alertmanager-irc-relay">alertmanager-irc-relay</a>. This IRC channel is also public: <a href="http://webchat.freenode.net/?channels=%23sr.ht.ops&amp;uio=d4">#sr.ht.ops on irc.freenode.net</a>.</p> <p>Prometheus normally works by pulling stats off of daemons, but we also want to monitor ephemeral or one-off tasks. For this purpose, we have also set up <a href="https://github.com/prometheus/pushgateway">Pushgateway</a>. We mainly use this to keep track of timestamps: the timestamp of the last backup, the last ZFS snapshot, or the expiration dates of our SSL certificates. For example, we can get <a href="https://metrics.sr.ht/graph?g0.range_input=30m&amp;g0.expr=time()%20-%20zfs_last_snapshot&amp;g0.tab=0">the age of our ZFS snapshots</a> in seconds with this query:</p> <pre tabindex="0"><code>time() - zfs_last_snapshot </code></pre><p><img src="https://l.sr.ht/6HPu.svg" alt="An SVG showing the age of ZFS snapshots across the fleet"></p> <p>This is trivially populated with a simple cronjob:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="cp">#!/bin/sh -eu </span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="nv">host</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>hostname -f<span class="k">)</span><span class="s2">&#34;</span> </span></span><span class="line"><span class="cl">stats<span class="o">()</span> <span class="o">{</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;# TYPE zfs_last_snapshot gauge\n&#39;</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;# HELP zfs_last_snapshot Unix timestamp of last ZFS snapshot\n&#39;</span> </span></span><span class="line"><span class="cl"> <span class="nv">ts</span><span class="o">=</span><span class="k">$(</span>zfs list -HS creation -o creation -t snapshot <span class="p">|</span> head -n1<span class="k">)</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;zfs_last_snapshot{instance=&#34;%s&#34;} %d\n&#39;</span> <span class="s2">&#34;</span><span class="nv">$host</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="nv">$ts</span><span class="s2">&#34;</span> </span></span><span class="line"><span class="cl"><span class="o">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">stats <span class="p">|</span> curl --data-binary @- https://push.metrics.sr.ht/metrics/job/<span class="s2">&#34;</span><span class="nv">$host</span><span class="s2">&#34;</span> </span></span></code></pre></div><p>Our backup age is filled in at the time the backup is taken with something like this:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="cp">#!/bin/sh -eu </span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="nb">export</span> <span class="nv">BORG_REPO</span><span class="o">=</span><span class="c1">#...</span> </span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">BORG_PASSPHRASE</span><span class="o">=</span><span class="c1">#...</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="nv">backup_start</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>date -u +<span class="s1">&#39;%s&#39;</span><span class="k">)</span><span class="s2">&#34;</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;borg create&#34;</span> </span></span><span class="line"><span class="cl">borg create <span class="se">\ </span></span></span><span class="line"><span class="cl"><span class="se"></span> ::git.sr.ht-<span class="s2">&#34;</span><span class="k">$(</span>date +<span class="s2">&#34;%Y-%m-%d_%H:%M&#34;</span><span class="k">)</span><span class="s2">&#34;</span> <span class="se">\ </span></span></span><span class="line"><span class="cl"><span class="se"></span> /var/lib/git <span class="se">\ </span></span></span><span class="line"><span class="cl"><span class="se"></span> <span class="c1">#...</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;borg prune&#34;</span> </span></span><span class="line"><span class="cl">borg prune <span class="se">\ </span></span></span><span class="line"><span class="cl"><span class="se"></span> --keep-hourly <span class="m">48</span> <span class="se">\ </span></span></span><span class="line"><span class="cl"><span class="se"></span> --keep-daily <span class="m">60</span> <span class="se">\ </span></span></span><span class="line"><span class="cl"><span class="se"></span> --keep-weekly <span class="m">24</span> <span class="se">\ </span></span></span><span class="line"><span class="cl"><span class="se"></span> --info --stats </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">stats<span class="o">()</span> <span class="o">{</span> </span></span><span class="line"><span class="cl"> <span class="nv">backup_end</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>date -u +<span class="s1">&#39;%s&#39;</span><span class="k">)</span><span class="s2">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;# TYPE last_backup gauge\n&#39;</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;# HELP last_backup Unix timestamp of last backup\n&#39;</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;last_backup{instance=&#34;git.sr.ht&#34;} %d\n&#39;</span> <span class="s2">&#34;</span><span class="nv">$backup_end</span><span class="s2">&#34;</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;# TYPE backup_duration gauge\n&#39;</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;# HELP backup_duration Number of seconds most recent backup took to complete\n&#39;</span> </span></span><span class="line"><span class="cl"> <span class="nb">printf</span> <span class="s1">&#39;backup_duration{instance=&#34;git.sr.ht&#34;} %d\n&#39;</span> <span class="s2">&#34;</span><span class="k">$((</span>backup_end-backup_start<span class="k">))</span><span class="s2">&#34;</span> </span></span><span class="line"><span class="cl"><span class="o">}</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">stats <span class="p">|</span> curl --data-binary @- https://push.metrics.sr.ht/metrics/job/git.sr.ht </span></span></code></pre></div><p>In addition to alarming if the age gets too large, the duration allows us to graph trends in the backup cost so that we can make informed judgements about the backup schedule:</p> <p><img src="https://l.sr.ht/wC9J.svg" alt="An SVG showing the duration of backups. git.sr.ht takes the longest at about 3000 seconds."></p> <p>Backups are of critical importance in our ops plan, so we have redundant monitoring for them. This is where the other emails you saw on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-ops">sr.ht-ops</a> come into play. We configured <a href="https://zfsonlinux.org/manpages/0.8.0/man8/zed.8.html">ZFS zed</a> to send emails to the mailing list on ZFS events, and left debug mode on so that it&rsquo;s emailing us even when there are no errors. We set up a cronjob to run a scrub on the 1st of the month, and the resulting zed emails are posted to the ops list. We also do weekly borg backup checks, which are posted to the mailing list every Sunday night.</p> <p>Reliability is important to us. SourceHut is still an alpha, but a robust approach to reliability is considered a blocker for the production phase, and taking the development of this approach seriously during the alpha and beta periods. You can read up more on our ops work at our public <a href="https://man.sr.ht/ops/">operations manual</a>. And it&rsquo;s working — we have 99.99% uptime for 2020, and have only suffered one unplanned partial outage this year.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> Let&rsquo;s aim for 99.999% in 2021!</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>Unfortunately, this and Twilio are the only parts of the stack which are not open source. Replacing Twilio would be hard but I bet Automate is low-hanging fruit - <a href="mailto:[email protected]">suggestions would be welcome!</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>Two pages were affected, and it lasted 46 minutes. We fixed the problem, prevented future problems of the sort, and added new alarms which would catch a broader net of problems in the future. <a href="https://status.sr.ht/issues/2020-06-28-unplanned-git.sr.ht-outage/">Read the details here</a>.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on Sourcehut? June 2020 https://sourcehut.org/blog/2020-06-15-whats-cooking-june-2020/ Mon, 15 Jun 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-06-15-whats-cooking-june-2020/ <p>Hello! With May behind us and July looming, we have another month of progress on the alpha in our cap. Today we&rsquo;re joined by 695 new users, bringing our total strength to 15,458 brave hackers. Give our new peers a warm welcome, please!</p> <h2 id="general-news">General news</h2> <p>Please be advised that today, June 15th, starting at 18:00 UTC, we have a planned outage. Services are expected to be intermittently available for a period of up to an hour. Each outage is expected to be limited to one service at a time, and should last no more than 15 to 30 minutes each. Consult the <a href="https://status.sr.ht/issues/2020-06-15-planned-outage/">status page</a> for more information.</p> <p>I&rsquo;d also like to thank Eli Schwartz once again, for stepping up as the new official maintainer of the SourceHut Arch Linux package distribution. He will be handling the maintenance of the Arch Linux repository going forward; please direct your inquiries and patches to him. Thanks Eli!</p> <h2 id="metasrht">meta.sr.ht</h2> <p>A new GraphQL API for meta.sr.ht is now available. <a href="https://meta.sr.ht/graphql">Play with it here!</a> As promised in the last update, the GraphQL playground is now JavaScript-free. I am also working on an improved means of API authentication, with finer-grained access controls and more compatibility with industry standards like OAuth2.</p> <p>If you&rsquo;re curious to learn more about the application of GraphQL to SourceHut, I wrote <a href="https://sourcehut.org/blog/2020-06-10-how-graphql-will-shape-the-alpha/">a blog post</a> on the subject last week.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>The manifest submission page has replaced ace.js with CodeMirror for the JavaScript-enabled build manifest editor. This should work better on mobile devices and feels a bit more native to use (because it is a bit more native). As before, users with JavaScript disabled will still be able to use a plain textarea to submit build manifests.</p> <ul> <li>alpine/3.12 is now available</li> <li>openbsd/6.7 is now available</li> <li>openbsd/6.5 has been removed</li> </ul> <h2 id="dispatchsrht">dispatch.sr.ht</h2> <p>Builds submitted for GitHub pull requests now include the <code>GITHUB_PR_BODY</code> in the environment, thanks to Paul Spooren&rsquo;s patches for OpenWRT. Thanks Paul!</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Ivan Habunek has implemented support for previewing the rendered Markdown for ticket descriptions and comments, and it was further refined by René Wagner. Gabriel Augendre also rigged it up so that you&rsquo;re copied on tickets submitted by email, so you get the ticket number that was assigned sent back to you, and Benjamin Lowry submitted several bug fixes. Thanks, everyone!</p> <h2 id="gitsrht">git.sr.ht</h2> <p>The GraphQL API has grown support tag artifacts, and learned many bug fixes. Thanks for helping to test this!</p> How and why GraphQL will influence the SourceHut alpha https://sourcehut.org/blog/2020-06-10-how-graphql-will-shape-the-alpha/ Wed, 10 Jun 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-06-10-how-graphql-will-shape-the-alpha/ <p>Often I will remind users that SourceHut is an &ldquo;alpha-quality product&rdquo;, even though many people are already using it today and find it well-suited to their present needs. What I mean by this is to remind you that, while many things already work, I am still working on refining the implementation before we commit to the design going forward. This foundational work is more important than many high-level features, because it will give us the basis from which the broader SourceHut platform is built and extended upon well into the future.</p> <p>Almost all of SourceHut today is built with Python, Flask, and SQLAlchemy, which is great for quickly building a working prototype. This has been an effective approach to building a &ldquo;good&rdquo; service and understanding the constraints of the problem space. However, it&rsquo;s become clear to me that this approach isn&rsquo;t going to cut it in the long term, where the goal is not just &ldquo;good&rdquo;, but &ldquo;excellent&rdquo;. The system would become more stable with the benefit of static typing, and more scalable with a faster and lighter-weight implementation. My work on SourceHut has, on the whole, really soured my opinion of Python as a serious language for large projects.</p> <p>One of the core requirements for the alpha to graduate to &ldquo;beta&rdquo; is the implementation of complete APIs throughout the services, both for users to access and for the services to use to communicate with each other. The lackluster state of these APIs was the main motivator for some of the large-scale changes I have planned. Originally I choose to use REST for the API, because REST is boring and well-understood. Boring, well-understood approaches are the bread and butter of SourceHut. However, I have been very unsatisfied with the results, and have been unwilling to take this design forward into the beta. During the alpha is the best time to reconsider this approach and build a more sustainable API design.</p> <p>Enter <a href="https://graphql.org">GraphQL</a>. I have considered GraphQL a few times in the past, but choose not to research it further for a number of reasons:</p> <ul> <li>The quality of server implementations has been rather poor on each of my research attempts, especially outside of JavaScript implementations.</li> <li>The ecosystem is heavily influenced by a web development culture which is flatly rejected by SourceHut&rsquo;s ethos. This leaks into the documentation and resources available for GraphQL, which makes it more difficult to evaluate through the lens of SourceHut&rsquo;s more conservative values.</li> <li>GraphQL does not solve many of the problems I would have hoped it would solve. It does not represent, in my opinion, the ultimate answer to the question of how we build a good web API. Therefore, someday there may come a better technology to supplant it, which makes me hesitate to base a long-term system design on it.</li> <li>The uptake of GraphQL in the general web ecosystem has been somewhat slow. The value-add is difficult to understand and even more difficult to implement well, making it difficult for all but senior engineering teams to understand.</li> </ul> <p>However, with my dissatisfaction with the REST approach reaching its peak in the past few months, I gave it a more serious and in-depth review. I built a research GraphQL API for git.sr.ht, trudging through the docs and specs with the aim of understanding it from the SourceHut perspective and how it could apply to our outlook on software design. I also found (or designed) solutions to some of the limitations of GraphQL which make me more confident that we can build a future-proof solution which is not going to feel outdated or bad when The Next Thing comes along. And, importantly, a new server-side implementation called <a href="https://gqlgen.com">gqlgen</a> has appeared since my last attempt, which, although imperfect, is good enough for me to consider it seriously as the basis for a large system.</p> <p>Another (potential) advantage of GraphQL is the ability to compose many different APIs into a single, federated GraphQL schema. If this pans out, it would be very convenient to access all of the distributed SourceHut services as a single cohesive system, trivially composing each service or subset of services as appropriate to the particular SourceHut deployment in question. Another area of research which may be improved by GraphQL are webhooks: I want to experiment with registering your webhooks with a GraphQL query, so that the webhook payload can contain all of the information you need to process the event without any additional API requests.</p> <p>In short, I&rsquo;ve concluded that GraphQL, while imperfect, is a significant advance in the state of the art from REST, and is mature and sophisticated enough to be useful as the basis of an API and an implementation that I can have long-term confidence in. This is important to get right, because the distributed design of SourceHut&rsquo;s mini-services demands high-quality communication between each component. I cannot feel comfortable moving forward from the alpha without this goal being met, and GraphQL makes me more confident in achieving it well.</p> <p>I also mentioned earlier that I am unsatisfied with the Python/Flask/SQLAlchemy design that underlies most of SourceHut&rsquo;s implementation. The performance characteristics of this design are rather poor, and I have limited options for improvement. The reliability is also not something I am especially confident in. The GraphQL work was not expected to solve this problem, but it may offer an unexpected solution.</p> <p>The GraphQL services are completely standalone, and it is possible to deploy them independently of the web application. With these, you can deploy a SourceHut instance with no frontend at all, using the GraphQL APIs exclusively. Today, the Python backends to the web services communicate directly with PostgreSQL via SQLAlchemy, but it is my intention to build out experimental replacement backends which are routed through GraphQL instead. This way, the much more performant and robust GraphQL backends become the single source of truth for all information in SourceHut. This could substantially increase my confidence in the system if it pans out — the Python footprint would become much smaller and simpler, and bugs in it would have less risk of creating inconsistent states in the system.</p> <p>These changes can be and will be made incrementally, and as a user, you should notice no changes other than improved performance and reliability, and access to better APIs. It is my intention to carry forward user data and continue to support existing projects throughout with no significant service disruptions. The performance and reliability of SourceHut today is already best in class, but I see no reason why we can&rsquo;t push the envelope even further. I also think that <a href="https://en.wikipedia.org/wiki/High_availability#Percentage_calculation">five nines</a> is an achievable goal.</p> <p>At the time of writing, there are two GraphQL APIs available for you to play with: <a href="https://meta.sr.ht/graphql">meta.sr.ht</a> and <a href="https://git.sr.ht/graphql">git.sr.ht</a>. These are still considered experimental, and some larger concerns such as write access and improvements to authentication remain to be implemented. Give it a shot and please share your feedback!</p> Achieving accessibility through simplicity https://sourcehut.org/blog/2020-05-27-accessibility-through-simplicity/ Wed, 27 May 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-05-27-accessibility-through-simplicity/ <p>I have received many emails complimenting SourceHut&rsquo;s simple design and lightweight pages<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, but I have received a surprising amount of positive feedback from a particular group of users: the blind community.</p> <p>For many software teams, especially web developers, accessibility is an extremely burdensome task. Many companies have written checks with an uncomfortable number of zeroes on them to get the job done. Sprinkling <a href="https://en.wikipedia.org/wiki/WAI-ARIA">ARIA tags</a> all over your DOM to annotate elements with their purpose, and updating these as your DOM changes over time, is no small task, and makes your code more difficult to maintain. It&rsquo;s not especially surprising that many blind users are constantly frustrated when trying to use the web.</p> <p>How did SourceHut make such an accessible website, even in the face of these trials? In truth, even though accessibility is important to me, I haven&rsquo;t worked especially hard to make SourceHut accessible — I have devoted no more than three or four hours, in total, explicitly towards accessibility. Instead, SourceHut is accessible because the core principles of simplicity upon which it is built naturally lead to an accessible design. We&rsquo;re here today to share our thoughts so that you might apply the same principles to your own website.</p> <p>First, consider the audience you&rsquo;re designing for. Your users have a diverse set of abilities, and a varied approach to accessibility is necessarily required to accommodate for them. Different users will have a different experience with your website. There are different levels of visual impairment — near- and far-sighted users, colorblind users, and many degrees of vision impairment ahead of totally blind. Talking about accessibility might bring forth thoughts of the latter group, but a lot of users with partial sight would also benefit if you put care into your visual design. There&rsquo;s also other considerations than vision — for example, avoid high precision mouse actions for users with limited mobility, and add subtitles to videos for the deaf and hard of hearing.</p> <p>For general advice on web accessibility, I would start with the following: &ldquo;trust the web browser&rdquo;. Leave the page at its default font size and avoid using custom fonts, preferring to use vague selections like &ldquo;sans-serif&rdquo; and &ldquo;monospace&rdquo;. Don&rsquo;t mess about with the scroll wheel, don&rsquo;t override default behaviors on the right click and text selection. Don&rsquo;t use JavaScript to create custom input elements like text boxes, combo boxes, or scrollbars. The web browser will do all of these things for you — trust it to do a good job.</p> <p>Remember that the browser is the <em>user</em> agent, not the <em>developer</em> agent. By trusting its defaults, you leave room for users to customize them, choosing a larger text size, a different font, and so on. The user is already comfortable with the way their browser works, and you will fail to capture the subtle nuances of their user agent with your pretty imitations. When accurately using the mouse is a struggle, a user who has gotten used to using the arrow keys in a <code>&lt;select&gt;</code> box is faced with an unreasonable challenge when they encounter a custom drop-down that hasn&rsquo;t implemented this behavior quite right.</p> <p>Another case to be careful of is the use of color, contrast, and images. Always make sure that text the user is expected to read is sufficiently distinguishable from its background.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> Also avoid putting text over a variable background, such as a gradient or tiled background. Be conservative with your use of color — limit bright, visually attractive colors to one or two actionable items on the page, or use them to draw special attention to timely notices, or to warn the user of potentially dangerous actions like deleting data.</p> <p>Try not to use a purely visual representation of information, such as an icon: these should always be paired with text. Such explanatory text shouldn&rsquo;t require, for example, hovering to see it — a task which requires high mobility to hit a small target with the mouse, and holding it steady for long enough to make a tooltip appear. Also avoid <em>moving</em> information around — animations and visually complex state transitions. When adding images, always include an &ldquo;alt&rdquo; tag with a plain-English description of the image.</p> <p>Do this exercise with me: cross your eyes, then close one eye. Through this blurry view, can you still identify the major elements and action items on your page? Does anything demand too much or too little attention?</p> <p>The &ldquo;alt&rdquo; tag reference a moment ago is the first time we&rsquo;ve touched upon many of the conventionally repeated wisdoms about &ldquo;accessibility&rdquo; on the web, often included because its value is intuitive and easy to implement. It&rsquo;s no mistake that we&rsquo;ve covered little of such conventional wisdom so far: the typical user who benefits from an accessible website is not completely blind, using a screen reader and taking advantage of your ARIA tags. The hard truth is that you just have to make your website simpler and easier to use — for everyone.</p> <p>But, it wouldn&rsquo;t do to forget the users with screen readers in any case. Some general advice for such users would be to make good use of semantic HTML, such as <code>&lt;main&gt;</code>, <code>&lt;article&gt;</code>, <code>&lt;section&gt;</code>, <code>&lt;nav&gt;</code>, and so on; along with other elements like <code>&lt;p&gt;</code> to mark paragraphs, <code>&lt;ul&gt;</code> and <code>&lt;ol&gt;</code> as appropriate to mark lists of things, <code>&lt;blockquote&gt;</code> for, well, quotes, and so on. Screen readers can interpret these to understand the layout of your page better and provide contextual clues to the user.</p> <p>Prefer to organize your site&rsquo;s information <em>logically</em>, rather than <em>spatially</em>. A logical hierarchy of information is more intuitive if you have less visual awareness. Make sure your page is organized so that if read linearly, from start to finish, without CSS, it still makes sense. Avoid littering marketing garbage, superlatives, and ads for other parts of the site (or even ads outright) throughout your page, as skipping these is more difficult for a screen reader than for the typical visitor. A good way of simulating the screen reader experience is to view your page with <a href="https://lynx.browser.org">Lynx</a>. Conveniently, Lynx does not support JavaScript. 😉</p> <p>This seems like a lot of effort to go to for accessibility! But, if you read closely, this is mostly a list of things to <em>avoid</em> doing. The SourceHut approach side-steps many of these problems by focusing on simplicity. The JavaScript-free interface is more accessible right out of the gate, and by not cramming too much into a single page it&rsquo;s much easier to flow and organize in an accessible way. This advice also leaks quite generally into the broader subject of <em>usability</em>, which is no mistake: investing in accessibility makes your service better for everyone.</p> <p>SourceHut also benefits from some design choices which extend beyond the web. For example, by focusing on email for discussions, patches, and code review, and <a href="https://useplaintext.email">insisting on plain text</a>, many blind users can choose to completely side-step the web interface and interact with the services and users on it from the comfort of their mail client, using only Plain Jane Text emails. Then, when they have questions, they can join our IRC chat room, a medium used exclusively to exchange short, plain-text messages, without the nightmare of navigating the Slack interface with a screen reader.</p> <p>In summary, if you want to get accessible quick, a good start for your new website might eschew <code>npm install</code> in favor of this:</p> <pre tabindex="0"><code>&lt;!doctype html&gt; &lt;html lang=&#34;en&#34;&gt; &lt;meta charset=&#34;utf-8&#34; /&gt; &lt;title&gt;My cool website!&lt;/title&gt; &lt;main&gt; &lt;h1&gt;My cool website&lt;/h1&gt; &lt;p&gt;Welcome to my cool website! &lt;/main&gt; </code></pre><p>Which, in case you were unaware, is a completely valid HTML 5 document!</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>And, to be fair, a handful of emails to the contrary, too.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>The Lighthouse tests built into Chrome-derived web browsers can be used to help identify UI elements with too-low contrast.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> The PeerTube content bootstrap fund https://sourcehut.org/blog/2020-05-15-peertube-bootstrap-fund/ Fri, 15 May 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-05-15-peertube-bootstrap-fund/ <p><a href="https://joinpeertube.org/en/">PeerTube</a> is an excellent project which aims to create an open and decentralized video &ldquo;tube&rdquo; for hosting video content with distributed governance and community-driven development. Chocobozzz, with the help of dozens of contributors, has put in the hard engineering work to build a great platform, and now we want to see it filled with content.</p> <p><strong>Notice</strong>: the first round of applicants has been processed. Check back in later - we may ask for more applications in the future.</p> <p><img class="inline-img" src="https://l.sr.ht/bLsu.jpg" alt="A graph of PeerTube instances each connected to one another" /></p> <style> .inline-img { width: 35%; float: right; margin: 0 -5rem 1rem 1rem; } @media(max-width: 800px) { .inline-img { display: block; width: 50%; width: auto; float: none; margin: 0 auto; } } </style> <p>To help make this happen, <strong>SourceHut is committing $5,000 to bootstrap content on the PeerTube network</strong>. This money will be used to help new content creators start making videos for PeerTube. We&rsquo;ll pay for some equipment to get you started: cameras, microphones, video capture cards, and so on, whatever is appropriate for the kind of videos you intend to make, plus a $200 budget to spend at your discretion on the first few videos. Need a nice camera? A couple of nice microphones for conducting interviews? A drone for capturing footage? Let&rsquo;s make it happen. You&rsquo;ll also be set up on <a href="https://liberapay.com/">Liberapay</a> so that your audience can help you build a sustainable lifestyle.</p> <p>If you have an interesting hobby to share, in-depth knowledge on a subject to teach, or a talent you&rsquo;d like to show off, or a great idea we haven&rsquo;t thought of, please send an email to <a href="mailto:[email protected]">[email protected]</a> with the subject line &ldquo;PeerTube bootstrap application: &lt;your name&gt;&rdquo;. Include a short summary of who you are and why you want to apply, and details on what kinds of videos you&rsquo;d like to make. Tell us why open culture is important to you.</p> <p>The following conditions apply:</p> <ul> <li>You must not already be regularly publishing content on another platform. We&rsquo;re looking to fund new content creators, not existing ones.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></li> <li>You can only upload videos to PeerTube - not to YouTube or anywhere else.</li> <li>Your videos must use a <a href="https://creativecommons.org/">Creative Commons</a> license, like <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC-BY-NC-SA</a>.</li> <li>We expect you to make at least 5 videos. If you decide video creation isn&rsquo;t for you after that, we&rsquo;ll take the equipment back and you&rsquo;ll be off the hook.</li> <li>Once you start earning at least $20/month on Liberapay, we&rsquo;ll split the ongoing cost of hosting evenly among all creators: currently $45/mo. You will never be expected to pay more than 25% of your Liberapay income; SourceHut will cover the rest.</li> </ul> <p>Our instance is at <a href="https://spacepub.space">spacepub.space</a>. We&rsquo;ll handle the technical administration of the server and set you up with the resources you need to get started, and together we&rsquo;ll create a community of open-culture creators who support one another to produce a vibrant commons. Let&rsquo;s help make PeerTube a great platform!</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>If you&rsquo;ve already made a few videos on the side, that&rsquo;s fine - be sure to let us know in your application, and we&rsquo;ll exercise discretion.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on Sourcehut? May 2020 https://sourcehut.org/blog/2020-05-15-whats-cooking-may-2020/ Fri, 15 May 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-05-15-whats-cooking-may-2020/ <p>Greetings! Another month of alpha development progresses and brings us that much closer to the SourceHut beta. We reached a few important milestones this month! Today we are 14,763 users strong, with 1,104 new users joining us this month. Please give them a warm welcome!</p> <h2 id="general-news">General news</h2> <p>Quick thanks to Eli Schwartz for patches across the board which simplify the installation process and improve support for a broader variety of distributions. Thanks also to Daniel Gröber and Thorben Günther for additional improvements in the installation process and self-hosted SourceHut experience.</p> <h2 id="hubsrht">hub.sr.ht</h2> <p>As you likely are already aware, the SourceHut project hub was opened this month. Since its opening, users have added 215 of their projects to the <a href="https://sr.ht/projects">public index</a>. If you want to add your project, <a href="https://sr.ht/projects/create">create a project</a> and complete the new project checklist to be added to the index. And, be sure to check out (and contribute to!) the cool projects other users have made! If you want to know more about the project hub and the future plans for it, read up on the <a href="https://sourcehut.org/blog/2020-04-30-the-sourcehut-hub-is-live/">original announcement</a>.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>The experimental <a href="https://graphql.org">GraphQL</a> API I&rsquo;ve alluded to in previous &ldquo;what&rsquo;s cooking&rdquo; posts is now available for users to play around with. It&rsquo;s still subject to change, but please take a look and share any feedback you have. I have deployed the GraphQL Playground at <a href="https://git.sr.ht/graphql">git.sr.ht/graphql</a> for you to play with. Unfortunately, this is a big JavaScript SPA, entirely atypical of the SourceHut web design ethos — but rest assured that before the GraphQL workstream is done, this will have been replaced with an in-house UI which better meets your expectations.</p> <p>The other major improvements I have planned for GraphQL include an overhaul to authentication, and a gateway through which all sr.ht APIs can queried through a single GraphQL request. On the whole I&rsquo;m pretty satisfied with the implementation, and I&rsquo;m optimistic that it will provide a much better foundation for the API going forward into the beta. It should open the doors to a lot of interesting future features as well. I will be doing a write-up on GraphQL for the sourcehut.org blog in the foreseeable future, so keep your eyes peeled for that if you&rsquo;re curious to learn more.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>The 9front distribution of Plan 9 is now available for user builds. This is an unusual build target; check out the <a href="https://sourcehut.org/blog/2020-05-11-sourcehut-plus-plan-9/">release announcement</a> to learn how it works. Other build image updates:</p> <ul> <li>nixos/20.03 has been added and nixos/stable has been updated to it; nixos/19.03 has been removed</li> <li>ubuntu/lts now refers to Ubuntu Focal</li> <li>dockerd now starts up correctly in Alpine Linux and Debian guests; Alpine is now the recommended guest for builds utilizing Docker</li> </ul> <p>Thanks to Francesco Gazzetta, Denis Laxalde, and Ace Eldeib for their patches this month.</p> <h2 id="hgsrht">hg.sr.ht</h2> <p>Ludovic Chabant has been hard at work on bugfixes and performance improvements for hg.sr.ht. The changes are subtle, but users should notice faster pushes at least.</p> SourceHut + Plan 9 = ❤ https://sourcehut.org/blog/2020-05-11-sourcehut-plus-plan-9/ Mon, 11 May 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-05-11-sourcehut-plus-plan-9/ <p>My favorite operating system is <a href="https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs">Plan 9 from Bell Labs</a>. The simplicity and cohesive design throughout really stands out. In my opinion, Plan 9 is much, much better than any other operating system I&rsquo;ve used, and I&rsquo;ve used a lot of operating systems. Plan 9 is not perfect, but it&rsquo;s a substantial advance to the state of the art.</p> <p><img src="https://l.sr.ht/pYgO.jpg" alt="A picture of Glenda, the Plan 9 mascot"></p> <p>Bell Labs has moved on, but <a href="http://9front.org">9front</a> keeps the dream alive as the most active (and sarcastic) fork of Plan 9. In the vain hopes that more people will become interested in Plan 9, and to provide better support to the existing community, and because I was bored, I spent some time this weekend adding 9front support to builds.sr.ht, providing the world&rsquo;s first continuous integration service for Plan 9.</p> <p>Here&rsquo;s an example build manifest for Plan 9:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">9front</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">tasks</span><span class="p">:</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">build</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd"> </span></span></span><span class="line"><span class="cl"><span class="sd"> cd / </span></span></span><span class="line"><span class="cl"><span class="sd"> . /sys/lib/rootstub </span></span></span><span class="line"><span class="cl"><span class="sd"> cd /sys/src </span></span></span><span class="line"><span class="cl"><span class="sd"> mk nuke </span></span></span><span class="line"><span class="cl"><span class="sd"> mk all</span><span class="w"> </span></span></span></code></pre></div><p>The source code for 9front is installed on every system at <code>/sys/src</code>, so, as you may have guessed, this build manifest compiles the operating system from source. This includes the C compiler and linker, assembler, kernel, and userspace; including Python 2, several game console emulators, and of course DOOM and Quake — <a href="https://builds.sr.ht/~sircmpwn/job/204643">in 115 seconds</a>.</p> <p>Plan 9 is very different. It&rsquo;s not POSIX, and not even Unix, and you can&rsquo;t approach it expecting to use or even port any of the software you&rsquo;re used to. Plan 9 is best appreciated on its own merits, and you should think in terms of what new things you can do with it, rather than what old things you can force into it. If you want to check it out, go into it expecting to learn — not to mold it into something familiar.</p> <p>Many staples of the modern software industry trace their lineage to Plan 9. The Go programming language is a direct descendant of Plan 9, along with Linux and BSD&rsquo;s /proc filesystems, user namespaces, and more. Even if you&rsquo;ve never heard of Plan 9, you&rsquo;ve been affected by it. Consider submitting a few builds to play around with it!</p> Announcing the SourceHut project hub https://sourcehut.org/blog/2020-04-30-the-sourcehut-hub-is-live/ Wed, 29 Apr 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-04-30-the-sourcehut-hub-is-live/ <p>I&rsquo;m happy to announce that the SourceHut project hub is now available for general use! This is one of the most important developments in the progress of the SourceHut alpha thus far. If you want to see how it works interactively, try checking out the <a href="https://sr.ht/~sircmpwn/sourcehut">SourceHut project</a>, <a href="https://sr.ht">add your own projects</a>, or <a href="https://sr.ht/projects">browse the public project index</a>. For a more wordy introduction, read on.</p> <p><img src="https://l.sr.ht/i0Uj.png" alt="Screenshot of the public project index on the SourceHut project hub"></p> <p>So why is the project hub necessary and/or interesting? SourceHut is composed of many small Unix-style tools for software development, which each &ldquo;do one thing and do it well&rdquo;. These tools are things like git hosting, bug tracking, mailing lists, CI, and so on. This allows you to use them independently and compose them however you please, which maps well onto the reality of how many projects are organized. Compare this to platforms like GitHub, GitLab, Gitea, and so on, where resources like bug trackers and pull requests map 1:1 to a git repository, even when it doesn&rsquo;t make sense.</p> <p>In reality, many projects have dozens of git repos but would prefer to receive bug reports in one place, for example. There are many ways projects are organized, and with a one-size-fits-all approach, many of them are forced to resort to meta-repositories, bots to chase down lost users posting things in the wrong place, and so on. Additionally, this insistence on a single git repo being the face of your project is very developer-centric. Only a fraction of visitors to your project actually want to browse the source code — many others are looking for documentation, bug reports, support channels, and so on; and frontloading the source code can be intimidating.</p> <p>The ability to freely compose resources on SourceHut to suit your project&rsquo;s needs addresses this. The primary disadvantage of our approach has been difficulty in finding out what resources belong to which projects, and getting around between them. The new project hub addresses this with a single &ldquo;hub&rdquo; for your project, with a more general introduction to the project and links to the each of the tools your project is using. You can have zero, one, or any number of git or Mercurial repos, mailing lists, and bug trackers, in any combination which is useful for your needs, and the project hub will organize them for you. It streamlines the workflow for new projects and will make it easier for new users to figure out how to get started on SourceHut.</p> <p>The project hub also solves a problem which has long been a matter of interest to SourceHut users: discoverability. How do you find what projects are hosted on the platform? The hub solves this with the <a href="https://sr.ht/projects">public project index</a>. Each public project which you create on the hub is listed here, and you can search through all of them to discover interesting projects to use or contribute to. I&rsquo;ve also added a list of featured projects, where I will be hand-picking interesting projects to share.</p> <p>This version of the hub is the <abbr title="Minimum Viable Product">MVP</abbr>, and there&rsquo;s more development I want to do in the future. Some of this includes:</p> <ul> <li>Adding project tags, like #python or #linux.</li> <li>Linking back to the parent project from resource pages.</li> <li>Handling more project resources, like wikis.</li> <li>RSS feeds everywhere!</li> </ul> <p>The hub also comes with smaller changes to the rest of the site — the &ldquo;sourcehut&rdquo; link on every page&rsquo;s navigation will now take you back to the hub, and hg.sr.ht has been made a first-class target in the nav.</p> <p>Please give the new service a shot and send along any feedback that comes to mind, via <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a> or by <a href="mailto:[email protected]">emailing me directly</a>. Enjoy!</p> Prioritizing simplicity improves performance and reliability https://sourcehut.org/blog/2020-04-20-prioritizing-simplitity/ Mon, 20 Apr 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-04-20-prioritizing-simplitity/ <p>We recently put together some automated testing which evaluates the performance of various software forges without bias<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>: the <a href="https://forgeperf.org">Software Forge Performance Index</a>. The goal is to push our community of software forges to strive for higher performance, to tighten your workflow loop and to better service communities without access to high-speed internet or newer computer hardware. I also included results for accessibility testing, hoping that we can push each other to improve on that front as well.</p> <p>These tests show that SourceHut has room for improvement. For one, some important features are conspicuously absent, like a git blame view. GitHub beats out our performance at rendering commits and tickets, and on several pages GitHub and Bitbucket both have better accessibility scores than the equivalent sr.ht page. But the overall results are clear: SourceHut is the best performing code forge, and by a wide margin. The data also shows that our approach delivers the best reliability: our friends at GitHub and GitLab have struggled with outages <a href="https://www.githubstatus.com">15 of the last 90 days</a> and <a href="https://status.gitlab.com/pages/history/5b36dc6502d06804c08349f7">18 of the last 90 days</a>, respectively. SourceHut has had <a href="https://status.sr.ht">two outages in 2020</a>, both of which were planned and announced a week in advance, and only one of which affected more than one subsystem.</p> <p>The secret is, as you may have guessed, to prioritize simplicity. It&rsquo;s all too easy for a development team to chase after shiny features — I know because it tempts me, too. But sooner or later the chickens come home to roost, and you have a giant single-page application downloading a megabyte of JavaScript and pinning a CPU for several seconds before the page is useful (if scrolling at 3 FPS can be considered useful).</p> <p>Every SourceHut page, on a cold cache, requires two HTTP requests to complete. On a warm cache, it requires only one. The typical sr.ht page is about 30 KiB. Both of these figures are ten times better (or, in some cases, <em>one hundred times</em> better) than the competition. Even with a cache, your web browser has to parse your JavaScript and CSS, warm up the JIT, run all of your initialization code&hellip; this stuff doesn&rsquo;t come for free, especially on anything but top-of-the-line hardware — which I know many of my peers <a href="https://drewdevault.com/2019/01/23/Why-I-use-old-hardware.html">are using</a>. There is a lot of developer attention on improving the performance of the status quo, but to earn the order-of-magnitude performance improvements SourceHut has, you need to make order-of-magnitude reductions in complexity.</p> <p>This culture of simplicity extends to our backend servers, too, which is how we deliver on reliability. We have no Kubernetes here, no Docker, no CloudFormation, no monorepos. SourceHut has 10 dedicated servers and about 30 virtual machines, all of which were provisioned by hand. We prefer <a href="https://alpinelinux.org">Alpine Linux</a> because it&rsquo;s lightweight and simple — our average production server has only 20 to 30 packages installed, which means no moving parts that we don&rsquo;t understand. Our application design helps as well: many pages are designed to make only one or two round-trips to the database, the queries for which can be carefully optimized with joins and indices built to-purpose.</p> <p>Our distributed &ldquo;miniservice&rdquo; application design also allows any of our services to fail independently without causing a total outage. And, because we embrace email for collaboration, our entire service could be offline without affecting your workflow — the email system has 50 years of battle-tested fault tolerance and redelivery mechanisms, you can keep working normally and our servers automatically get caught up when they&rsquo;re back online. We achieve reliability on several levels: simple servers which don&rsquo;t break unexpectedly, monitoring which alerts us to problems before they&rsquo;re serious, and a design which works even if we do experience an outage.</p> <p>Microsoft bought GitHub for 7 billion dollars. GitLab is valued at 3 billion dollars. Together, the two companies have over 2,000 employees. <a href="https://sourcehut.org/blog/2020-04-13-sourcehut-q1-2020-financial-report">SourceHut made 4 thousand dollars in Q1</a> with two employees and an intern. How do we deliver on this level of reliability and performance compared to these giants? The answer is a fundamental difference in our approach and engineering ethos. I hope that <a href="https://forgeperf.org">forgeperf.org</a> is a good start for pushing our industry to mount a serious attack on the eternal problems of high performance and reliability once more.</p> <p>If you want to learn more about our approach to reliability, check out our public <a href="https://man.sr.ht/ops/">operations manual</a>, join our #sr.ht.ops channel on irc.freenode.net to watch our operations in real-time, or query the raw monitoring data yourself from our <a href="https://metrics.sr.ht/graph">public Prometheus instance</a>.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>I am confident that these results are accurate and without bias towards SourceHut. We run only standard benchmarks, maintained by a neutral third-party (Google Lighthouse), and the results are corrected for latency and bandwidth differences. This was verified by having the same test suite run in several locations across America and Europe, showing consistent results even with more generous routing to our competitors. You can run it, too, and verify the results for yourself — it&rsquo;s pretty easy to set up the software on Linux and it only takes about an hour to produce the full report. I&rsquo;m also sure that the results are not cherry-picking pages for which SourceHut has an advantage — it&rsquo;s easy to contribute new pages if you think we missed a spot.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on Sourcehut? April 2020 https://sourcehut.org/blog/2020-04-15-whats-cooking-april-2020/ Wed, 15 Apr 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-04-15-whats-cooking-april-2020/ <p>Greetings! Another month passes and we progress closer still to the beta. We are joined by 464 new users, bringing our new total to 13,659. Please provide them with a warm welcome!</p> <h2 id="general-news">General News</h2> <p>In case you missed it, be sure to check out the <a href="https://sourcehut.org/blog/2020-04-13-sourcehut-q1-2020-financial-report/">Q1 Financial Report</a>, published earlier this week. In other general news, I recently overhauled our <a href="https://man.sr.ht/installation.md">installation instructions</a>, bringing them up to date with changes since their original time of writing, and completing the documentation overhaul I had planned. I hope you find these useful! We were getting tired of correcting the docs all the time in IRC as people were setting up their sr.ht instances.</p> <p>Additionally, throughout the site small improvements have been made: tables in Markdown have been improved, as well as relative links and embedded images from git repositories. The OAuth implementation has been brought more into compliance with RFC 6750, and there have been minor improvements for logged-out users. Small responsiveness improvements have also shipped throughout, improving the UI for mobile users.</p> <h2 id="hubsrht">hub.sr.ht</h2> <p>hub.sr.ht is going quite well, and I hope to have an initial version online for you to start using by the time I write the next edition of &ldquo;What&rsquo;s cooking&rdquo;. I&rsquo;ve summarized the current state of the project in this video:</p> <video src="https://yukari.sr.ht/hub.sr.ht.webm" controls muted> Your web browser does not support the webm video codec. Please consider using web browsers that support free and open standards. </video> <p>There still remains a significant amount of work to do, but for the most part it&rsquo;s clearly defined and just needs to be executed.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>After 6 months of work, five patches across 3 different projects, and several thousand lines of code, I have finished <a href="https://github.com/libgit2/pygit2/pull/982">adding custom backend support</a> to <a href="https://www.pygit2.org/">pygit2</a>, which unblocks a number of workstreams. Accordingly, I&rsquo;ve completed the first of these new workstreams by introducing a new plumbing API to git.sr.ht, which offers low-level access to git resources. The rub is that you can create a custom pygit2 backend implementation which allows you to read and manipulate git repositories like normal, but rather than storing the repository on your local filesystem, it reaches out to the git.sr.ht API to complete I/O operations remotely. This plumbing API remains undocumented for the time being, but I hope to eventually stabilize it and make it available to you for your own needs. I&rsquo;m also happy to share that SourceHut has become the first sponsor of the pygit2 project <img src="https://sourcehut.org/party.png" style="display: inline-block; height: 1.25rem; position: relative; top: 0.25rem; box-shadow: none;" /></p> <p>I have also begun work on a second API-related project, with git.sr.ht as the testbed. The current set of APIs offered on SourceHut have long since left their proof-of-concept stage and are now implemented broadly enough to pull their drawbacks into relief. There&rsquo;s no time which will be more perfect to revisit the API design than during the alpha, when breaking changes are more tolerable. To this end, I&rsquo;ve been writing an experimental GraphQL-based API for git.sr.ht in Go. My initial impressions are very optimistic — I&rsquo;ll write up my thoughts on GraphQL in more detail later — and I think this would be a marked improvement over our REST-based approach today, and maps very well onto our distributed system design. If you&rsquo;re curious about this work, you can see the current status on the <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/log/graphql">graphql branch</a> of git.sr.ht. The schema itself can be found <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/graphql/api/graph/schema.graphqls">here</a>.</p> <p>The approach isn&rsquo;t fully defined yet — there&rsquo;s a lot of experimental code throughout, and it&rsquo;s changing rapidly. Writing this backend in Go also gives me the opportunity to revisit a lot of drawbacks in the Python codebase, and the result is a lot leaner and meaner than the earlier implementation. If this ends up working out, we would be wise to invest more in this architecture.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Image updates:</p> <ul> <li><code>freebsd/current</code> has been removed. If you had used this image in the 30 days preceding its deprecation, you should have received an email letting you know. If you run into any additional issues, be sure to reach out on <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a></li> </ul> <p>Some minor performance improvements to the web UI have also shipped this month.</p> Sourcehut Q1 2020 Financial report https://sourcehut.org/blog/2020-04-13-sourcehut-q1-2020-financial-report/ Mon, 13 Apr 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-04-13-sourcehut-q1-2020-financial-report/ <p>In summary, SourceHut is financially healthy.</p> <p>Before we get into the stuffy business stuff, let&rsquo;s get the inevitable out of the way. I hope that your family and friends are safe as you read this. I&rsquo;m sure that many people reading today&rsquo;s financial report are facing uncertain financial times for themselves. If this is the case for you, don&rsquo;t hesitate to cancel your SourceHut subscription. We will be alright — take care of yourself and your loved ones first. On the other hand, if you are secure and want to help, we would appreciate it if you bought a paid subscription.</p> <p>Eventually, payment to SourceHut will become mandatory. This was expected to occur when the alpha graduated to the beta. However, if we find ourselves amend a continued global crisis as the software matures to beta, we will postpone making payments mandatory. And, as always, anyone with extenuating circumstances is not expected to pay, even when it becomes &ldquo;mandatory&rdquo;.</p> <p>Stay safe, and thank you for your continued support.</p> <small> Disclaimer: this report is a summarized approximation of our financials, and is not used for tax purposes. </small> <h2 id="revenue-sources">Revenue sources</h2> <p>Sourcehut receives revenue from paid user subscriptions. During Q1, we processed 1,673 invoices. The invoices paid break down as:</p> <pre><code>823 $2 (paid monthly) 382 $5 (paid monthly) 135 $10 (paid monthly) 228 $2 (paid yearly) 71 $5 (paid yearly) 34 $10 (paid yearly) </code></pre> <p>The total gross revenue during this period was $16,486.00, which after transaction fees comes out to $15,108.98. This is a 30% decrease from last quarter, and a 163% increase compared to Q1 last year. This is accounted for by our annual subscriptions - our yearly invoices due each quarter in 2020 break down as follows:</p> <pre><code>Q1 194 Q2 50 Q3 151 Q4 608 </code></pre> <p>Yearly payments have an outsized effect on the total cash flow, and this accounts for the reduction in income for Q4 2019 → Q1 2020. These figures are in line with our expectations for Q1. 1,377 new users registered accounts in Q1, of which 156 (11%) have paid for their account. As of the end of Q1, there were 13,418 registered users in total, of which 1,553 (12%) have paid subscriptions.</p> <p>At time of writing (2 weeks into Q2 2020), the breakdown of subscription types is as follows:</p> <pre><code> $2 monthly 282 users $2 yearly 751 users $5 yearly 254 users $5 monthly 136 users $10 monthly 45 users $10 yearly 98 users </code></pre> <p>The monthly revenue from these subscriptions (with annual subscriptions realized over 12 months) is approximately $4,649, after transaction fees. This is a $534 increase in monthly revenue compared to Q4.</p> <p>Sourcehut has $13,792 in the bank at the time of writing (2020-04-13).</p> <h2 id="expenses">Expenses</h2> <p>Breakdown of Q4 expenses:</p> <pre><code>$3303 New server equipment (git.sr.ht) $1950 Philadelphia datacenter lease (inc. network, power, etc) $ 981 San Francisco datacenter lease (inc. network, power, etc) $ 490 Misc. hardware $ 334 Travel (FOSDEM) </code></pre> <p>Note that we paid the 2020 lease for the San Francisco datacenter in full in Q1, as opposed to our typical quarterly payments.</p> <p>Payroll:</p> <pre><code> $5,500.00 Payroll +$ 179.07 Employer taxes &amp; processing fees </code></pre> <p>Going into Q2, our monthly expenses are expected to be:</p> <pre><code>$3500/mo Payroll (approximate) $640.00/mo Philadelphia datacenter lease </code></pre> <p>We have postponed our plans to hire another engineer. Our financial projections have not yet predicted a downturn in SourceHut&rsquo;s economic viability, but we are a risk-averse business. We are moving onto a more conservative financial footing in preparation for whatever economic consequences of the COVID-19 pandemic may come to pass.</p> What's cooking on Sourcehut? March 2020 https://sourcehut.org/blog/2020-03-15-whats-cooking-march-2020/ Sun, 15 Mar 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-03-15-whats-cooking-march-2020/ <p>Hello! This has been a very busy month for SourceHut. Thank you for supporting it during the alpha! Today our users are 13,195 in number, with 438 new users joining us since our last status update. Please give them a warm welcome!</p> <h2 id="general-news">General News</h2> <p>I&rsquo;ve spent a lot of time this month working on a bunch of operations-related tasks, such as monitoring and backups improvements. Our backup system is now triple-redundant and kept in check by three separate monitoring systems. You&rsquo;ll see some of these reports on our public <a href="https://lists.sr.ht/~sircmpwn/sr.ht-ops">operations mailing list</a>, or can dig into the raw data on our public <a href="https://metrics.sr.ht">Prometheus instance</a>. I&rsquo;ve also written up an <a href="https://man.sr.ht/ops/">operations manual</a> to keep track of our approach and future plans for operations, so that you can be aware of what steps we&rsquo;re taking to keep things up and running, and perhaps apply our techniques to your own self-hosted instances of SourceHut.</p> <p>This month also saw design discussions on sr.ht-discuss regarding the eventual design and implementation of user groups (or &ldquo;organizations&rdquo;), and how they&rsquo;ll affect billing, access control lists, reserved CI slots, and so on. Check out the archives for more: <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CC0L8LGIM0C2I.3O209D1TSO6M3%40homura%3E">the initial proposal</a>, and <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CC0WZSZTLDP8B.34K9PQFW7NTHB%40homura%3E">version 2</a>.</p> <p>We also deployed some improvements to responsiveness throughout the site, which you&rsquo;ll probably have already noticed if you&rsquo;re on mobile. Mobile users aren&rsquo;t the only group to benefit, however: I took extra time to make sure the interface looks good at any subset of a 4K monitor, so our tiling window manager users can have a comfortable interface with a web browser at half-width or less.</p> <p>Finally, we have a new mail server in place, which should be a little bit more maintainable going forward, and our legacy infrastructure has finally been overhauled. These were our last two servers which were not running on the standard Alpine-based load-out<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. This unblocks&hellip;</p> <h2 id="srht">sr.ht</h2> <p>Finally, work has commenced on the central project hub. This will solve the problems of discoverability of projects hosted on SourceHut, searching for new projects site-wide, linking together bug trackers and git repos, and more. This project is ostensibly called &ldquo;hub.sr.ht&rdquo; internally, but the intention is to deploy it at the top-level domain: sr.ht.</p> <p><img src="https://legacy.sr.ht/RUcZ.jpg" alt=""></p> <p>The hub will let you create a central hub for your project, with any combination of zero, one, ten, or more git and hg repos, bug trackers, mailing lists, and so on. You can add exactly what you need, as much as you need, and nothing you don&rsquo;t need. This is why SourceHut is designed the way it is today. Many large projects have dozens of source repos, and giving each one their own bug tracker, pull requests, documentation, website, and so on, does not map to the actual project structure and frequently leads to clunky workflows on other hosts. The SourceHut project hub solves this problem better.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Following up on our recent git.sr.ht change to allow users to attach binary releases to git tags, I&rsquo;ve implemented build artifacts for our CI as well. By adding a list of artifacts to your build manifest, you can have the files extracted from the build VM after successful builds and made available for download on the web or inspection via the API. Artifacts are kept for 90 days, but in the future I would like to let you indicate that certain artifacts should be kept permanently. <a href="https://man.sr.ht/builds.sr.ht/manifest.md#artifacts">Docs are available here</a>.</p> <p>I also provisioned a new build server this month, and as part of our ops work I&rsquo;ve <a href="https://man.sr.ht/ops/provisioning.md#build-hosts">documented its specs here</a>. This will increase our build throughput quite a bit, to better support our growing base of high-demand CI projects, including <a href="https://builds.sr.ht/~araq/nim">Nim</a>, <a href="https://builds.sr.ht/~jmk/neovim">NeoVim</a>, and <a href="https://builds.sr.ht/~puffy-bot/opensmtpd">OpenSMTPD</a>.</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>With the exception of ns1.sr.ht and ns2.sr.ht, which are still running Debian. These are slated for upgrade, but are not urgent.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What do we do when you lose your 2FA codes? https://sourcehut.org/blog/2020-03-04-when-you-lose-2fa/ Wed, 04 Mar 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-03-04-when-you-lose-2fa/ <p>By far the most common sort of support request I receive from SourceHut users on a day-to-day basis is from users who have lost access to their TOTP (<a href="https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm">Time-based One-time Password algorithm</a>) codes. Losing your phone, getting a new one and forgetting to migrate the keys, or wiping it to install a new OS are common reasons to accidentally lose access to your two-factor authentication.</p> <p>Naturally, we cannot just disable 2FA on your account, no questions asked. The purpose of 2FA is to increase the level of scrutiny that&rsquo;s placed on attempts to make authorized requests for your account. Therefore, we seek some alternative method of authenticating that you are who you say you are.</p> <p>The easiest way is PGP: about 10% of sr.ht users have added a PGP key to their account. If your support email is signed with the PGP key we have on file for you, then we can assume it&rsquo;s you with no further questioning. If not, we can ask you to send a follow-up email which is signed. Even more users have an SSH key added to their account, about 30%. For them, I asked my friend minus to write a small tool, <a href="https://git.sr.ht/~minus/sshign">sshign</a>, which can cryptographically sign messages with your SSH key.</p> <div class="alert alert-info"> You can add PGP and SSH keys to your account on the <a href="https://meta.sr.ht/keys" rel="nofollow noopener" target="_blank" >key management page</a>. </div> <p>Those strategies are my preference, but there are still a fair number of users who need 2FA turned off but haven&rsquo;t added any keys to their account. I have to get more creative with these. One way I&rsquo;ll often choose is looking at the website added to their profile page. If they can add a file to the website or update a DNS record in response to a challenge, then that&rsquo;ll often be sufficient.</p> <p>One thing we used to do, but no longer, is to ask you for the last four digits of the credit card number on file for your account. I have known other services to use a similar approach. Eventually I decided to stop using this, because it&rsquo;s fairly easy to get the last 4 of your CC# from anywhere you&rsquo;ve used it. This information has been leaked from many services after many security incidents. I will, however, use this much information to cancel your subscription payment upon request.</p> <p>There are a small number of users who ask to have 2FA reset, but have little-to-no secondary information to their account. For these few, there is no recourse — I have to tell them that I cannot help them regain access to their account. I doubt any of these folks have actually not been the authentic owner of their respective accounts, but the security of 2FA rests on this extra level of additional scrutiny.</p> What's cooking on Sourcehut? February 2020 https://sourcehut.org/blog/2020-02-15-whats-cooking-february-2020/ Sat, 15 Feb 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-02-15-whats-cooking-february-2020/ <p>Hello again! Another month into 2020, and SourceHut development continues at a strong pace - a pace I expect to pick up a bit in the coming weeks. We&rsquo;re joined by another 443 users this month, bringing our total to 12,757. Welcome to SourceHut, everyone! And to our older members, thanks for your continued support.</p> <h2 id="general-news">General News</h2> <p>Our meetup at FOSDEM went well - thanks to everyone who attended! I&rsquo;m glad I got to meet more of you in person, and we had a great chat going over the plans for the future and getting your feedback on what&rsquo;s important to you.</p> <p>In terms of general development, there are a few news items. First, you will probably have noticed that subtle design changes landed throughout the services early this month. These changes brought us into 100% compliance with the WCAG accessibility standards, which is a feat that no other code forge can claim. We score higher now on standard tests of performance, accessibility, and web standards than any other code hosting service. SourceHut is now objectively the fastest, lightest, and most accessible service in the biz. I even fielded a bug report from a Lynx user last week!</p> <p>Search support has also been improved throughout the site thanks to Ivan Habunek&rsquo;s hard work, and special thanks to Denis Laxalde as well for his improvements to builds.sr.ht search. Documentation for the new features is coming soon.</p> <p>I&rsquo;ve also been working with some community contributors whose aim is to improve Markdown support across the site, bringing support for CommonMark and aligning our implementation more closely with what you may have come to expect from your experiences on the rest of the web. These require changes careful testing, so please be patient while we work on them.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>A cool new git.sr.ht feature landed this week: attaching files to annotated git tags. This allows you to attach compiled executables, PGP signatures, and so on to your releases. Check out the <a href="https://man.sr.ht/git.sr.ht/#attaching-files-to-releases">user documentation here</a>, and the <a href="https://man.sr.ht/git.sr.ht/api.md#post-apireposusernamereposnameartifactsref">API docs here</a>. This is the first of several planned features which utilize the new blob storage infrastructure - additional features coming soon include git-lfs support, build artifacts, build caches, and a &ldquo;SourceHut Pages&rdquo;-like service.</p> <p>More subtle changes to git.sr.ht include detecting if your repository has a license, which leads to <a href="https://man.sr.ht/license.md">our wiki page with suggestions on how to choose one</a>. I also added support for LibreJS for the few (optional) bits of JavaScript on git.sr.ht, which along with the other changes brings <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3CC03B4X6WE7XN.9NAXAORGDJ0B%40homura%3E">SourceHut&rsquo;s score for the GNU ethical repository criteria</a> into pretty good standing.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Denis Laxalde, in addition to his work on improving builds.sr.ht search functionality, has also implemented RSS feeds for each page. You can obtain RSS feeds for your user page, any combination of build tags (useful for per-project RSS feeds), and for arbitrary search queries. Thorben Günther also implemented a small bugfix which resolved a long puzzling issue with build status emails - related to UTF-8 email addresses.</p> <p>Image-specific updates:</p> <ul> <li>Debian builds with custom repositories now also automatically include the source repos.</li> <li>FreeBSD builds no longer use <code>-cpu qemu64</code>, following upstream fixes to AMD EPYC support.</li> <li>OpenBSD images now include X11 headers.</li> </ul> What's cooking on Sourcehut? January 2020 https://sourcehut.org/blog/2020-01-15-whats-cooking-january-2020/ Wed, 15 Jan 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-01-15-whats-cooking-january-2020/ <p>Welcome to 2020! We kick off our first status update of the year with a community 12,314 users strong, up 387 from our last update of 2019. A warm welcome to all of our new members, and a big thanks to everyone for continuing to use and support SourceHut. This month was heavy on operations work, so this update is light on new features - but we&rsquo;re turning our attention back to feature development in the coming weeks.</p> <h2 id="general-news">General News</h2> <p>We&rsquo;re going to <a href="https://fosdem.org/2020/schedule/event/bof_sourcehut/">FOSDEM</a> again this year! We&rsquo;ll be in the J.1.106 room on February 1st at 12:00 PM. Come join us, we&rsquo;ll be giving away stickers, answering questions, and showing off some of our upcoming plans.</p> <p>Last week, I finished overhauling our monitoring &amp; alarming infrastructure, and the new setup is <a href="https://metrics.sr.ht">available to the public</a> for inspection. I&rsquo;m also working on opening up more ops work to improve transparency in this respect: the <a href="irc://irc.freenode.net/sr.ht.ops">#sr.ht.ops channel</a> on Freenode is now open to the public, and I&rsquo;ve also established the public <a href="https://lists.sr.ht/~sircmpwn/sr.ht-ops">sr.ht-ops mailing list</a>. I&rsquo;ve updated our alarms to send notifications to #sr.ht.ops and to the sr.ht-ops mailing list, and directed some of our cronjobs to the public mailing list as well, so you can keep abreast of things like backup integrity and get greater insights into outages and load. Our <a href="https://git.sr.ht/~sircmpwn/metrics.sr.ht">alertmanager rules</a> are also public, and you can drop these into your own infrastructure to add similar monitoring to your third-party instance.</p> <p>Work is ongoing to add more instrumentation throughout SourceHut, stay tuned. As part of this work, we also upstreamed several monitoring-related packages to Alpine Linux, and upgraded all of our machines to Alpine 3.11 (and Python 3.8).</p> <h2 id="gitsrht">git.sr.ht</h2> <p>We <em>finally</em> were able to source the remaining parts for the new server hardware we needed to completely resolve the performance issues you were likely experiencing with git.sr.ht. The new server is blazing fast! Thanks for your patience, I know it was frustrating before. It should be plenty fast now. Aside from some minor bugfixes and upgrades to support pygit2 1.x and Alpine 3.11, there&rsquo;s not much else to discuss for git.sr.ht. Some of these improvements have been making their way into hg.sr.ht, so expect performance to gradually improve there as well.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Some great news here: you can now re-import the tracker exports which were implemented last month, to recreate deleted trackers, migrate trackers between accounts, or even between SourceHut instances. This month I&rsquo;m focusing on accomplishing our data ownership goals, so you should see improvements like this throughout the services in the coming weeks. Ivan Habunek also implemented some nice changes, notably adding rendered markdown previews for comments.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>The alpine/3.11 image is now available, and alpine/latest now refers to it. alpine/edge has been updated to use the linux-lts kernel from edge.</p> Sourcehut Q4 2019 Financial report https://sourcehut.org/blog/2020-01-13-sourcehut-q4-2019-financial-report/ Mon, 13 Jan 2020 00:00:00 +0000 https://sourcehut.org/blog/2020-01-13-sourcehut-q4-2019-financial-report/ <p>In summary, Sourcehut is financially healthy. We have a reduced services profit from Q3 - we are currently breaking even - but this is due to a planned increase in expenses and is offset by revenue from our new consultancy. Growth has continued at a similar pace to Q3. Through the recent formalization of the <a href="https://sourcehut.org/consultancy">SourceHut free software consultancy</a>, we have also raised a significant amount of capital, which increases our runway substantially, and allows us to consider more hires, new hardware provisioning, and so on. 2019 was a great year for SourceHut, and I summarized our accomplishments and goals in <a href="https://sourcehut.org/blog/2019-11-15-sourcehut-1-year-alpha/">this earlier article</a>.</p> <p>Thank you for your support in the alpha. I&rsquo;m looking forward to continuing to serve you in 2020.</p> <p>Disclaimer: this report is a summarized approximation of Sourcehut&rsquo;s financials, and is not used for tax purposes.</p> <h2 id="revenue-sources">Revenue sources</h2> <p>Sourcehut receives revenue from paid user subscriptions. During Q4, we processed 1,824 invoices. The invoices paid break down as:</p> <pre><code>803 $2 (paid monthly) 372 $5 (paid monthly) 102 $10 (paid monthly) 373 $2 (paid yearly) 128 $5 (paid yearly) 45 $10 (paid yearly) </code></pre> <p>The total gross revenue during this period was $22,856.00, which after transaction fees comes out to $21,530.35. Because of differences in the volume of yearly invoices processed during Q4, this number is not easily compared with Q3. It&rsquo;s better to compare it with Q4 2018 — when compared to this, we&rsquo;ve shown ~185% growth.</p> <p>In Q4, 1,876 new users registered accounts, of which 267 (14%) have paid for their account. As of the end of Q4, there were 12,289 registered users in total, of which 1,410 (11.4%) have paid subscriptions.</p> <p>At time of writing (2 weeks into Q1 2020), the breakdown of subscription types is as follows:</p> <pre><code>279 $2 (paid monthly) 126 $5 (paid monthly) 38 $10 (paid monthly) 660 $2 (paid yearly) 228 $5 (paid yearly) 79 $10 (paid yearly) </code></pre> <p>The monthly revenue from these subscriptions (with annual subscriptions realized over 12 months) is approximately $4,115, after transaction fees. This is a $808 increase in monthly revenue compared to Q3.</p> <p>Sourcehut has $25,442 in the bank at the time of writing (2020-01-13).</p> <p>Breakdown of Q4 expenses:</p> <pre><code>$4504 New server equipment (git.sr.ht) $1950 Philadelphia datacenter lease (inc. network, power, etc) $ 812 Travel (FOSDEM) $ 548 Insurance renewal $ 129 San Francisco datacenter lease (inc. network, power, etc) $ 38 Misc. equipment </code></pre> <p>Payroll:</p> <pre><code> $5,500.00 Payroll +$ 179.07 Employer taxes &amp; processing fees </code></pre> <p>Going into Q4, our monthly expenses are expected to be:</p> <pre><code>$3500/mo Payroll (approximate) $640.00/mo Philadelphia datacenter lease $129/qtr San Francisco datacenter lease </code></pre> <p>At the end of Q3, we were preparing to learn how we would be impacted by the first round of annual subscription renewals, unsure of how many users would cancel. We did not see any unusual number of subscription cancellations in Q4, and it does not impact our financial planning.</p> <p>At some point in early 2020, we are planning on hiring an additional engineer. We also expect to spend a bit more on FOSDEM before it&rsquo;s over.</p> <h2 id="consultancy">Consultancy</h2> <p>This is the first quarter during which our free-software consultancy has factored into our finances. Our core mission is to elevate the free software community, and part of our long-term plans have been to hire free software developers to work full-time on self-directed projects. The consultancy helps us meet this goal — 100% of the work is free software, on projects relevant to our engineers, chosen at their discretion. Additionally, we pass most of the hourly rate onto the engineer, which offsets our industry substandard salary. The profits are also reinvested into free software, helping us hire additional engineers.</p> <p>However, reporting on our consulting work is not as straightforward as our other financial reporting. The income of the consultancy is not consistent and predictable like our paid services are. In terms of financial planning, the profits are treated as additional runway or capital. Runway is how we measure the longevity of the business in rainy day scenarios, and capital is sums of money we pull from to finance new hardware, new hires, and so on.</p> <p>Because most of the revenue is directly passed onto the individual engineers, sharing it in too much detail raises privacy concerns. We&rsquo;re working on figuring out how to be more transparent with this side of the business, but it will likely not be possible until we have more engineers on board to help anonymise the numbers.</p> What's cooking on Sourcehut? December 2019 https://sourcehut.org/blog/2019-12-15-whats-cooking-december-2019/ Sun, 15 Dec 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-12-15-whats-cooking-december-2019/ <p>This is our last &ldquo;what&rsquo;s cooking&rdquo; of 2019! We&rsquo;re seeing out the year with 11,927 registered users, 563 stronger than November. Please give our new members a warm welcome! We have some cool progress on many fronts this month.</p> <h2 id="general-news">General News</h2> <p>First of all, we finally got single-sign-on sorted out this month. Now, logging in once will log you in everywhere. Many other problems which stemmed from this have also been fixed - long time users will no doubt have seen the &ldquo;log out and back in to enable builds.sr.ht integration&rdquo; message on a git push, but thankfully that annoyance will be unknown to new users going forward. This was also a pre-requisite for dealing with user groups, which will be the next main focus of account management work.</p> <p>I&rsquo;ve also been experimenting with Ceph and preparing to provision our new Ceph cluster, which will give us three things: (1) object storage, (2) filesystem storage, and (3) block device storage. Each of these separately unblocks a number of features. (1) gives us things like attaching binaries to tags or publishing build artifacts from builds.sr.ht jobs, (2) gives us things like a GitHub-pages-style feature, and (3) can be leveraged for build caches. Ceph is complicated and I want this deployment to be sustainable indefinitely, so I&rsquo;m going to take my time to provision it carefully and understand every piece - so please have patience while I get this set up.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>The first series of performance improvements to git.sr.ht landed this month, and I wrote <a href="https://sourcehut.org/blog/2019-11-22-what-happens-on-git-push/">an article</a> which goes into a great deal of detail for the curious. The next step is to improve the I/O throughput of the server, which can only be done with revprovisioning. Unfortunately, the hardware to do this has been a real pain in the ass to obtain - SuperMicro has been having issues with their fulfillment pipeline recently and I&rsquo;m struggling to complete the build. We may be in for a bit of a wait while I try to get the parts together. If I don&rsquo;t have this squared away by January, I&rsquo;m going to redesign the server with different parts. I already have half of the parts, and I&rsquo;d rather they don&rsquo;t go to waste, so I&rsquo;m going to spend a little more time trying to get this system built per the original specification.</p> <h2 id="listssrht">lists.sr.ht</h2> <p>You can now grant a new access control privilege to users: &ldquo;moderate&rdquo;. This allows users to update patchset status and remove emails from the archives.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Minor maintenance updates:</p> <ul> <li>Debian packages are now available.</li> <li>Fedora 31 is now available.</li> <li>FreeBSD 12.1 is now available.</li> <li>NixOS 19.09 is now available.</li> <li>OpenBSD 6.6 is now available.</li> </ul> <h2 id="namessrht">names.sr.ht</h2> <p>Wow, this is complicated. I think having an open-source implementation of all of these rules will be a boon to the ecosystem, though. Despite the complexity, I still have a reasonably complete image of what the system should look like in my head, and we&rsquo;re slowly progressing towards realizing it. Here&rsquo;s another screenshot to tease you in the meanwhile:</p> <p><a href="https://sr.ht/LLkW.png"><img src="https://sr.ht/LLkW.png" alt="Screenshot of domain contacts on names.sr.ht"></a></p> What happens when you push to git.sr.ht, and why was it so slow? https://sourcehut.org/blog/2019-11-22-what-happens-on-git-push/ Fri, 22 Nov 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-11-22-what-happens-on-git-push/ <p>One of the most persistent, frustrating, and entirely valid, criticisms of Sourcehut that I&rsquo;ve heard has been that git operations over SSH are too slow. The reason this is a frustrating complaint to hear is that the git.sr.ht SSH pipeline is a complicated set of many moving parts, and fixing the problem involved changes at every level. However, as many of you will (hopefully) have noticed by now, pushing to and pulling from git.sr.ht is quite snappy now! So after a huge amount of work overhauling everything to get us here, I thought it would be nice to reflect on what caused these issues, how this system is structured, and how the problem was eventually solved.</p> <p>There are several major tasks that need to happen when you push or pull to git.sr.ht. In order, they are:</p> <ol> <li><strong>Dispatch</strong> Which system are you SSHing into? git.sr.ht? builds.sr.ht?</li> <li><strong>Identification</strong> Who are you?</li> <li><strong>Authorization</strong> Are you allowed to do what you&rsquo;re trying to do?</li> <li><strong>Execution</strong> Hand things off to git to complete your operation.</li> <li><strong>Follow-up</strong> Do we need to submit any CI jobs? Webhooks?</li> </ol> <p>During each of these steps, your terminal is blocked. You have to wait for all of them to complete. Well, most of them, at least. Let&rsquo;s discuss each step in detail.</p> <h2 id="dispatching">Dispatching</h2> <p>There are several Sourcehut services which you can log onto using SSH: git.sr.ht, hg.sr.ht, and builds.sr.ht, and perhaps more in the future. Before we overhauled it, man.sr.ht used to have a dedicated SSH service as well. In our case, we run each of these services on their own servers at their own IP addresses. However, this was not always the case, and we still support third-party installations of Sourcehut services which are all sharing a single server. Therefore, we have to have a way of identifying which service you&rsquo;re trying to SSH into, and for this purpose we use the user. You use <code>[email protected]</code>, <code>[email protected]</code>, and <code>[email protected]</code>, to log onto each respective service.</p> <p>This phase is handled by our <code>gitsrht-dispatch</code> binary, whose source code <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-dispatch/main.go">you can view here</a>. This is run by OpenSSH in order to generate an <code>authorized_keys</code> file, with a list of SSH keys which are allowed to log into Sourcehut. That&rsquo;s beyond the scope of dispatch, however, which delegates it to the next step. Instead, it just figures out which service it needs to hand you off to for authentication.</p> <pre><code>[git.sr.ht::dispatch] # # The authorized keys hook uses this to dispatch to various handlers # The format is a program to exec into as the key, and the user to match as the # value. When someone tries to log in as this user, this program is executed # and is expected to emit an AuthorizedKeys file. /usr/bin/gitsrht-keys=git:git /usr/bin/hgsrht-keys=hg:hg </code></pre> <p>When you SSH into the service as <code>git@...</code>, the dispatcher looks up the entry corresponding to the git user. In this case, it&rsquo;s <code>gitsrht-keys</code>. Then, it finds the uid and gid for this account, setuid<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>&rsquo;s itself to that user, and exec&rsquo;s<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> into the next step.</p> <h2 id="identification">Identification</h2> <p>Each discrete service is separately responsible for its own approach to identifying and authorizing users. OpenSSH executed our dispatcher hoping to get an authorized keys file, and the next step is to prepare one for it. For git.sr.ht, this responsibility falls onto <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-keys/main.go">gitsrht-keys</a>.</p> <p>This is where things start to get interesting in terms of performance. Ideally, we want to get out of here with zero round-trips to remote services like SQL. For this reason, we cache your SSH keys on a Redis instance at localhost. OpenSSH handed us your base64&rsquo;d SSH key and dispatch forwarded it to us, and we use this to look up your key from the cache. If we find it, we can skip directly to the final step. But, if we miss the cache, we ask meta.sr.ht if it&rsquo;s seen your key before. We then cache it in Redis and make sure we have a copy in our database as well, to save you time for the next push. But even in this worst case, we&rsquo;re already starting to see hand-optimized SQL queries:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- Getting the user ID is really a separate concern, but this saves us a </span></span></span><span class="line"><span class="cl"><span class="c1">-- SQL roundtrip and this is a performance-critical section </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">WITH</span><span class="w"> </span><span class="n">key_owner</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="p">(</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="n">user_id</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="p">.</span><span class="n">username</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">sshkey</span><span class="w"> </span><span class="p">(</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">user_id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">meta_id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">key</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">fingerprint</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">user_id</span><span class="p">,</span><span class="w"> </span><span class="err">$</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="err">$</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="err">$</span><span class="mi">4</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">key_owner</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- This no-ops on conflict, but we still need this query to complete so </span></span></span><span class="line"><span class="cl"><span class="c1">-- that we can extract the user ID. DO NOTHING returns zero rows. </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">ON</span><span class="w"> </span><span class="n">CONFLICT</span><span class="w"> </span><span class="p">(</span><span class="n">meta_id</span><span class="p">)</span><span class="w"> </span><span class="k">DO</span><span class="w"> </span><span class="k">UPDATE</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">meta_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">2</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">RETURNING</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">user_id</span><span class="p">;</span></span></span></code></pre></div> <p>We need to get your git.sr.ht user ID while we&rsquo;re here, and normally we&rsquo;d look it up in Redis. With this SQL query, we fetch the user ID at the same time as we store your key. This kind of hacky SQL packing is a common tactic we&rsquo;ll see employed throughout for improved performance.</p> <p>At the end of this process, we print out a generated authorized keys file and exit, then OpenSSH does the rest of the work to verify that the user actually possesses the private key they claim to and so on. Then, when they&rsquo;re allowed in, we move on to the shell.</p> <pre><code>restrict,command=gitsrht-shell,environment=&quot;SRHT_PUSH=&lt;uuid&gt;&quot;,your ssh key here </code></pre> <p>This keys file turns off almost all SSH features (restrict), overrides the command you will run to use our shell, and adds an assigned UUID for this push to the environment.</p> <h2 id="authorization">Authorization</h2> <p>At this point, we&rsquo;ve found your account and verified that you&rsquo;re an authorized agent of the user, using your SSH key. Now we need to know if you&rsquo;re allowed to do what you&rsquo;re trying to do, which is where <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-shell/main.go">gitsrht-shell</a> comes in. Its job is to look up the repository you&rsquo;re trying to do and compare the operation you want to perform (read or write) against the access control lists. Even in the best case, we&rsquo;re required to do a SQL round-trip here. This is what it looks like:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- Fetch the necessary info from SQL. This first query fetches: </span></span></span><span class="line"><span class="cl"><span class="c1">-- </span></span></span><span class="line"><span class="cl"><span class="c1">-- 1. Repository information, such as visibility (public|unlisted|private) </span></span></span><span class="line"><span class="cl"><span class="c1">-- 2. Information about the repository owner&#39;s account </span></span></span><span class="line"><span class="cl"><span class="c1">-- 3. Information about the pusher&#39;s account </span></span></span><span class="line"><span class="cl"><span class="c1">-- 4. Any access control policies for that repo that apply to the pusher </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">owner_id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">owner</span><span class="p">.</span><span class="n">username</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">visibility</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pusher</span><span class="p">.</span><span class="n">user_type</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pusher</span><span class="p">.</span><span class="n">suspension_notice</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">access</span><span class="p">.</span><span class="k">mode</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">repository</span><span class="w"> </span><span class="n">repo</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="w"> </span><span class="k">owner</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="k">owner</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">owner_id</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="w"> </span><span class="n">pusher</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">pusher</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LEFT</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="k">access</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="p">(</span><span class="k">access</span><span class="p">.</span><span class="n">repo_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="k">access</span><span class="p">.</span><span class="n">user_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">2</span><span class="p">;</span></span></span></code></pre></div> <p>Again, we&rsquo;ve jammed a lot of somewhat disjoint information into a single SQL query for efficiency&rsquo;s sake. We fetch everything we&rsquo;ll need to know later on: what&rsquo;s this repo&rsquo;s ID and name, who&rsquo;s the owner, what&rsquo;s the repo visibility, who&rsquo;s the pusher and what kind of user are they, is their account suspended and how do we break it to them if so, and are there any access list entries for them on this repository?</p> <p>There are two reasons that this could fail: the repository has been renamed, or it never existed. If this query returns no results, then we try to look for a redirect — round-trip #2. The query is as follows:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">owner_id</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">owner</span><span class="p">.</span><span class="n">username</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">visibility</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pusher</span><span class="p">.</span><span class="n">user_type</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">pusher</span><span class="p">.</span><span class="n">suspension_notice</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">access</span><span class="p">.</span><span class="k">mode</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">repository</span><span class="w"> </span><span class="n">repo</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="w"> </span><span class="k">owner</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="k">owner</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">owner_id</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="w"> </span><span class="n">pusher</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">pusher</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="n">redirect</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">redirect</span><span class="p">.</span><span class="n">new_repo_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">id</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LEFT</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="k">access</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="p">(</span><span class="k">access</span><span class="p">.</span><span class="n">repo_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="k">access</span><span class="p">.</span><span class="n">user_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">redirect</span><span class="p">.</span><span class="n">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">2</span><span class="p">;</span></span></span></code></pre></div> <p>You&rsquo;ll notice that we&rsquo;re also fetching a whole lot of information at once here. In case we do find a redirect, we don&rsquo;t want to do a third round-trip to fetch all the information we&rsquo;ll need for that repo, either.</p> <p>Say this fails, too. Now we definitely know that your repository doesn&rsquo;t exist. This is the point at which git.sr.ht&rsquo;s autocreate-repos-on-push feature kicks in, if the repo you&rsquo;re pushing to is under your user namespace. <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-shell/main.go#L263">That code is fairly simple and involves an additional round-trip</a>, you may study it in your own time.</p> <p>But, if we get this far, then we have everything we need to finish authorizing you. If you do have permission to complete the operation you&rsquo;ve requested, we exec into the appropriate git binary.</p> <h2 id="execution">Execution</h2> <p>At this point, you&rsquo;re in git&rsquo;s hands. We&rsquo;ve handed you off to one of their binaries to complete the push or pull operation. The tools that can be run at this point are <a href="https://git-scm.com/docs/git-receive-pack">git-receive-pack</a>, <a href="https://git-scm.com/docs/git-upload-pack">git-upload-pack</a>, or <a href="https://git-scm.com/docs/git-upload-archive">git-upload-archive</a> — follow the links if you want to learn more about them.</p> <h2 id="following-up-hooks">Following up: hooks</h2> <p>There&rsquo;s one last task for us to do before we can send you on your way, and it&rsquo;s split into three parts. These are our <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">git hooks</a>. These are only run on git pushes, not for fetching. We use these hooks to complete some housekeeping after your pushes complete, and to implement a few features. The remaining tasks for us to do at this point are:</p> <ol> <li>Update the mtime of your repository</li> <li>Submit any necessary builds.sr.ht jobs</li> <li>Deliver webhooks</li> </ol> <p>This doesn&rsquo;t seem like much, but it&rsquo;s in fact the most complicated part of the process so far. It&rsquo;s handled by <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-update-hook">gitsrht-update-hook</a>. These tasks correspond, though not 1:1, to three steps, each mapping to a different git hook:</p> <ol> <li>hooks/update</li> <li>hooks/post-update</li> <li>hooks/stage-3 (this is a pseudo-hook that we made up)</li> </ol> <p>The <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-update-hook/main.go">entry point</a> is pretty simple. It just figures out what stage we&rsquo;re on and changes its behavior accordingly. The first step, the <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-update-hook/update.go">update hook</a>, is really simple; we just use it to collect data from git for use in later stages. In theory we could reject your push here, but in practice we don&rsquo;t have anything set up to do so right now. git executes us once for every updated ref, with the old and new sha&rsquo;s for that ref, and we just shove them into a local Redis instance for later use.</p> <p>&ldquo;Later use&rdquo; comes with stage 2, the <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-update-hook/post-update.go">post-update hook</a>. This is where the majority of the work for this stage starts to get done. We first pull the &ldquo;push context&rdquo; out of the environment, which is some data that gitsrht-shell prepared for us earlier, to avoid fetching the same data in two different stages. We don&rsquo;t get off completely scot-free, though, and we hit the next required SQL round-trip:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- With this query, we: </span></span></span><span class="line"><span class="cl"><span class="c1">-- 1. Fetch the owner&#39;s username and OAuth token </span></span></span><span class="line"><span class="cl"><span class="c1">-- 2. Fetch the repository&#39;s name and visibility </span></span></span><span class="line"><span class="cl"><span class="c1">-- 3. Update the repository&#39;s mtime </span></span></span><span class="line"><span class="cl"><span class="c1">-- 4. Determine how many webhooks this repo has: if there are zero sync </span></span></span><span class="line"><span class="cl"><span class="c1">-- webhooks then we can defer looking them up until after we&#39;ve sent the </span></span></span><span class="line"><span class="cl"><span class="c1">-- user on their way. </span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">UPDATE</span><span class="w"> </span><span class="n">repository</span><span class="w"> </span><span class="n">repo</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SET</span><span class="w"> </span><span class="n">updated</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NOW</span><span class="p">()</span><span class="w"> </span><span class="k">AT</span><span class="w"> </span><span class="n">TIME</span><span class="w"> </span><span class="k">ZONE</span><span class="w"> </span><span class="s1">&#39;UTC&#39;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="p">(</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="p">.</span><span class="n">username</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="p">.</span><span class="n">oauth_token</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">repository</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">owner_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&#34;user&#34;</span><span class="p">.</span><span class="n">id</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">r</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="k">owner</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">FILTER</span><span class="p">(</span><span class="k">WHERE</span><span class="w"> </span><span class="n">rws</span><span class="p">.</span><span class="n">sync</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">true</span><span class="p">)</span><span class="w"> </span><span class="n">sync_count</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">FILTER</span><span class="p">(</span><span class="k">WHERE</span><span class="w"> </span><span class="n">rws</span><span class="p">.</span><span class="n">sync</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">false</span><span class="p">)</span><span class="w"> </span><span class="n">async_count</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">repo_webhook_subscription</span><span class="w"> </span><span class="n">rws</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">rws</span><span class="p">.</span><span class="n">repo_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">rws</span><span class="p">.</span><span class="n">events</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">&#39;%repo:post-update%&#39;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">webhooks</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">RETURNING</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">repo</span><span class="p">.</span><span class="n">visibility</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">owner</span><span class="p">.</span><span class="n">username</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">owner</span><span class="p">.</span><span class="n">oauth_token</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">webhooks</span><span class="p">.</span><span class="n">sync_count</span><span class="p">,</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">webhooks</span><span class="p">.</span><span class="n">async_count</span><span class="p">;</span></span></span></code></pre></div> <p>This query helps us determine what work we&rsquo;ll need to do in the rest of the process, and gets us some of the information we need to complete that work. We update the mtime of your repo, but we also do some hacky joins and subqueries to sneak more information out of SQL in one round-trip. We grab the OAuth key we&rsquo;ll need to submit builds on your behalf to builds.sr.ht, and the number of synchronous and asynchronous webhooks registered for your repository. If there are any synchronous webhooks, that means (by definition) that we need to complete those in this stage, and a second query is performed:</p> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">url</span><span class="p">,</span><span class="w"> </span><span class="n">events</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">repo_webhook_subscription</span><span class="w"> </span><span class="n">rws</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="n">rws</span><span class="p">.</span><span class="n">repo_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="mi">1</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">rws</span><span class="p">.</span><span class="n">events</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">&#39;%repo:post-update%&#39;</span><span class="w"> </span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">rws</span><span class="p">.</span><span class="n">sync</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">true</span><span class="p">;</span></span></span></code></pre></div> <p>Next, we open up your git repository to have a peek inside. We iterate over each ref which you updated during your push, and pull the old and new references out of Redis from stage 1. We pull some info out of git and turn it into a webhook payload to be delivered later, and we look for builds.sr.ht manifests. If we find one, we set up a <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-update-hook/submitter.go">build submitter</a> for it, and it kicks off any necessary CI jobs.</p> <p>That webhook payload we&rsquo;ve prepared now needs to be submitted to any synchronous webhooks before we let go of your terminal - after all, it&rsquo;s a feature that these webhooks can return some text to show to the pusher before they&rsquo;re off. The <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-update-hook/webhooks.go">webhook code</a> is pretty straightforward, with one minor exception: webhook payloads are signed.</p> <p>Once that&rsquo;s done, we can finally release your terminal and send you on your way. However, we&rsquo;re not done: we still have to run stage 3. Actually, we only have to run stage 3 if there were any synchronous or asynchronous webhooks on your repository. In the interests of speed, we don&rsquo;t record your synchronous webhook deliveries into SQL right away, and by definition we do your asynchronous deliveries asynchronously. So, we <a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-update-hook/post-update.go#L280">execute stage 3</a> as a detached child before we leave, and we send it any information we&rsquo;ve already collected for it to complete these tasks.</p> <p><a href="https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/gitsrht-update-hook/stage-3.go">Stage 3</a>&rsquo;s job can be undertaken at a much more leisurely pace. First, it looks up any asynchronous webhooks, then delivers the same payload to them, graciously forwarded by stage 2. It collects all of their deliveries, combines them with a list of deliveries forwarded from stage 2, and records them in SQL. Now, at long last, this lengthy process is complete.</p> <h2 id="so-why-was-everything-slow">So why was everything slow?</h2> <p>Well, for a few reasons. First, each step of this pipeline used to be written in Python, not Go, which matched the rest of Sourcehut&rsquo;s implementation. Spinning up the Python VM and pulling in all of our imports - including, for example, all of our SQLAlchemy riggings - is not cheap. Each of these steps would separately incur a startup cost on the order of up to a second each.</p> <p>Another reason is that the SQL riggings were not especially well optimized. In the worst case, it could take upwards of 20 SQL round-trips before your push operation was completed. This was mainly due to poor design choices, mostly motivated by DRY (Don&rsquo;t Repeat Yourself (Don&rsquo;t Repeat Yourself)), which tried to leverage more generalized and less efficient code used by the web application to perform some of these steps. In the best case, the new approach makes only one SQL round-trip for pulls, or 2 round-trips for a push.</p> <p>A major misstep was, in the process of optimizing these steps, the decision to move some of this logic into the web application. Python isn&rsquo;t very good at asynchronous operations, and Sourcehut&rsquo;s codebase pre-dates asyncio. We use Gunicorn as our web daemon, which runs several worker processes to handle web requests. At one point, to reduce the Python startup time, I thought it would be smart to bundle up all of your information in a little HTTP request and shoot it over to the web worker, which already had a SQL connection and a warm Python VM.</p> <p>However, the process was still very slow even with those bottlenecks removed - which was a huge problem. Because there are a fixed number of web workers, and they can only do one thing at a time, the addition of processing complicated git push logic to their workload would quickly pin workers, causing the web application <em>and</em> git pushes to slow. Before I fixed this mistake, the average time for an HTTP request and a git push were pushing 60 seconds. That was an awful, terrible, no good, very bad idea.</p> <h2 id="now-were-fast-or-are-we">Now we&rsquo;re fast! Or are we?</h2> <p>Astute observers and frequent git-pushers may notice that the ideal performance of git pushes on git.sr.ht have been vastly improved, to the point of often appearing instant, but they are not <em>consistently</em> that fast. There is one remaining bottleneck: I/O throughput. When git.sr.ht&rsquo;s servers are busy, we can still tie up I/O serving various other users before we get to your requests. This is a limitation of our current hardware deployment, which is more I/O bound than anything else. To address this last bottleneck, new server hardware is being provisioned, with different I/O constraints, and git.sr.ht will be moving to it as soon as it arrives and is put together. And then we&rsquo;ll be blazing fast, all the time, hooray! At least until we can afford better peering&hellip;</p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>setuid changes the user identity of the current process.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>exec replaces the current process with another.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> Sourcehut's year in alpha https://sourcehut.org/blog/2019-11-15-sourcehut-1-year-alpha/ Fri, 15 Nov 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-11-15-sourcehut-1-year-alpha/ <p>Today marks the 1 year anniversary of the commencement of <a href="https://drewdevault.com/2018/11/15/sr.ht-general-availability.html">Sourcehut&rsquo;s public alpha</a>, after 2 years in private development. I&rsquo;m immensely thankful for your support during the alpha. It&rsquo;s mostly been a one-man operation here, but thanks in large part to the financial support of the alpha users, I&rsquo;ve been able to work on Sourcehut and free software in general full-time for a full year as of this February. With this first year of the alpha behind us, what have we accomplished, and what do we have planned for 2020?</p> <p><em>Just looking for November&rsquo;s status update? <a href="#status-update">It&rsquo;s at the bottom, this a-way&hellip; ↓</a></em></p> <h2 id="2019-in-summary">2019 in summary</h2> <p>I&rsquo;m really proud of what we accomplished in 2019. Here are some of my personal favorite highlights:</p> <ul> <li>Deployment of APIs and webhooks throughout</li> <li>Establishing comprehensive systems monitoring</li> <li>Became profitable and self-sustaining</li> <li>Bringing on our first staff member</li> <li>Initial development of web-based code review within our design framework</li> <li>Maturation of <a href="https://todo.sr.ht">todo.sr.ht</a> into a great ticket tracking system</li> <li><a href="https://drewdevault.com/2019/07/08/Announcing-annotations-for-sourcehut.html">Code annotations</a> added for <a href="https://git.sr.ht">git.sr.ht</a></li> <li>SSH access to <a href="https://builds.sr.ht">builds.sr.ht</a> VMs for debugging and hacking</li> <li>Availability of Alpine, Arch, and Debian repositories for third-party sr.ht deployments</li> </ul> <p><em>Want to read plans for 2020? <a href="#expectations-for-2020">Skip the pretty pictures →</a></em></p> <p><img src="https://sr.ht/thL-.png" alt="SSH access to build VMs"></p> <em style="text-align: center; display: block"> <small>SSH access to a failed builds.sr.ht job</small> </em> <p><img src="https://sr.ht/w767.png" alt="Code annotations on git.sr.ht"></p> <em style="text-align: center; display: block"> <small>Browsing an annotated codebase on git.sr.ht</small> </em> <video src="https://sr.ht/_fUk.webm" controls muted> Your web browser does not support the webm video codec. Please consider using web browsers that support free and open standards. </video> <em style="text-align: center; display: block"> <small>Preparing patchsets to be emailed with git.sr.ht</small> </em> <p><img src="https://sr.ht/sjtE.png" alt="Code review thread parsing on lists.sr.ht"></p> <em style="text-align: center; display: block"> <small>Reviewing a patchset on the web with lists.sr.ht</small> </em> <h2 id="expectations-for-2020">Expectations for 2020</h2> <p>I believe Sourcehut will enter the beta phase in 2020, and be approaching the production phase by the end of the year. Some features I&rsquo;m looking forward to are:</p> <ul> <li>User groups/organizations</li> <li>A centralized project hub, bringing together our disparate services</li> <li>Data ownership and portability for all services</li> <li>Completed web-based patch submission/review</li> <li>Maturation of hg.sr.ht into a competitive Hg hosting service</li> <li>Integration with more projects throughout the software project hosting ecosystem</li> <li>The fruits of financially supporting free software developers — exactly what comes of this is unknown, but I&rsquo;m excited as hell about it.</li> </ul> <p>From developers sponsored by Sourcehut going into 2020, I&rsquo;m expecting to see more developments in Wayland and Linux graphics, mail clients <em>and</em> servers, improvements to Alpine Linux, <a href="https://mrsh.sh">mrsh</a>&rsquo;s completion and initial release, miscellaneous patches to any free software project which crosses our path, and new projects which I expect will pleasantly surprise us.</p> <p>Thank you to everyone for your support in our first year, and I&rsquo;m looking forward to continuing to serve you into the next. <img src="https://sourcehut.org/party.png" style="display: inline-block; height: 1.25rem; position: relative; top: 0.25rem; box-shadow: none;" /></p> <p>How exactly we&rsquo;re going to accomplish these goals is a subject worthy of some attention, too. I frequently get questions about the stability of the alpha, when the beta will come and how things will change, and so on. So, I&rsquo;ve taken this opportunity to write down The Master Plan.</p> <h2 id="development-roadmap">Development roadmap</h2> <p>First, briefly, the plan for Sourcehut&rsquo;s development lifecycle has been roughly:</p> <ol> <li>Build several standalone services which each solve a problem for software projects.</li> <li>Develop APIs and webhooks for each of these services.</li> <li>Teach them how to talk to each other, creating a complete system.</li> </ol> <p>We&rsquo;ve mostly completed phases 1 and 2 and development on phase 3 is underway.</p> <p><strong>Phase one</strong></p> <p>Base development of git.sr.ht, builds.sr.ht, lists.sr.ht, man.sr.ht, and more. This is close to complete, insofar as all of the unknowns are known. Some services are missing a few features which arguably fit into this step, such as git blame support for git.sr.ht, but for the most part everything is complete in its own right.</p> <p><strong>Phase two</strong></p> <p>This phase is the introduction of APIs and webhooks for every service, which is a necessary step before integrating everything together. The APIs and webhooks each service will use (and now, do use) to talk to each other are no different than those offered to end-users, which helps to prove the API design is flexible enough to support a broad variety of use-cases and integrations with other parts of the ecosystem.</p> <p>This phase is <em>mostly</em> complete — see the <a href="https://man.sr.ht/#service-documentation">API documentation links here</a> for an idea of which services have API coverage. The main exceptions are man.sr.ht and dispatch.sr.ht, which don&rsquo;t have an API because they&rsquo;re low-priority targets for integration with other services; and hg.sr.ht, which technically has an API that is mostly compatible with git.sr.ht&rsquo;s API but is left undocumented for want of an Hg specific API design document from the community.</p> <p>Building out these APIs also informed a lot of design decisions which helped to move the codebases from &ldquo;experimental&rdquo; into &ldquo;maintainable&rdquo;. In phase one, we establish the scope for each project and prove that its ideas are feasible, and in stage two we refined the prototypes into production-worthy systems.</p> <p><strong>Phase three</strong></p> <p>The final phase of development is perhaps the most exciting phase, as it&rsquo;s in this step that we get to deliver on many of the usability promises of Sourcehut. Some early progress has already been made in this direction. Some examples include:</p> <ul> <li>Teaching git.sr.ht &amp; hg.sr.ht to push CI jobs to builds.sr.ht</li> <li>Overhauling man.sr.ht to replace its internal git repos with git.sr.ht repos</li> <li>Teaching git.sr.ht to prepare and send patchsets to mailing lists, e.g. lists.sr.ht</li> </ul> <p>Future plans include tasks like:</p> <ul> <li>Teach lists.sr.ht how to submit CI jobs to validate incoming patchsets</li> <li>Teach lists.sr.ht how to merge patches to git/hg repos</li> <li>Refactor todo to use lists in a similar way to man&rsquo;s use of git</li> </ul> <p>An advantage of this three-stage approach is that each of these phase three features can, in theory, be extended to include other parts of the ecosystem. lists.sr.ht can be re-purposed to manage patches and code review for a Gitlab repository, builds.sr.ht can be used to run CI for GitHub repositories, git.sr.ht can be used to send patches to the Linux kernel, and so on. This is part of our commitment to embrace existing communities rather than building a new walled garden.</p> <h2 id="operations-roadmap">Operations roadmap</h2> <p>In addition to being a software project, Sourcehut offers a hosted service at sr.ht. The administration of this hosted service is another factor which requires planning and plays into the stability of the service. There are three major concerns of the operations roadmap:</p> <ul> <li>Security</li> <li>Data integrity</li> <li>Availability</li> <li>Monitoring</li> </ul> <p><strong>Security</strong> is the steps we take to ensure your account and its data is safe from malicious actors. This includes careful access controls - ensuring each system has access to only the data it needs; establishing trust levels and securing each system accordingly - for example, the multiple layers of isolation used for CI jobs on builds.sr.ht; and other miscellaneous concerns like secure SSH configuration, SSL maintenance, network administration, and so on.</p> <p><strong>Data integrity</strong> was important to address early in the alpha period, and has been essentially completed. For all persistent data, extreme pains are taken to ensure that it remains consistent even in emergencies - and our systems to ensure this have been battle tested <em>during</em> emergencies, including disk failures on critical machines. Our multiple layers of redundancy for data preservation were <a href="https://drewdevault.com/2019/01/13/Backups-and-redundancy-at-sr.ht.html">laid out in detail</a> in January and have only been improved since.</p> <p><strong>Availability</strong> is concerned with making sure that our services are always online, and during the alpha is a secondary concern. Our long-term goal is to approach zero downtime, by setting up load balancers and tiered deployments. Our software is designed with this in mind, which will ease the eventual deployment of high availability services. However, today we still have planned outages, and each deployment costs between 10 and 60 seconds of outage for the affected services.</p> <p><strong>Monitoring</strong> is a cross-cutting task which is essential to the success of the other goals. Setting up systems to observe and characterize the behavior of our services informs the planning and execution of security, data integrity, and availability goals. For example, we use monitoring to watch for suspicious activity, ensure our backups are up-to-date, and understand our system&rsquo;s load to prevent outages. This is mostly complete but alarming is due for an overhaul - Grafana alarms aren&rsquo;t great for serving all of our needs.</p> <p>An operations matter that was settled early and no longer factors into our planning is the release and deployment process for Sourcehut services. An acceptance requirement of builds.sr.ht&rsquo;s initial deployment was that it be self-hosted and self-deploying <em>and</em> support the deployment of *.sr.ht as well, and as such this goal was met before even the public alpha began.</p> <h2 id="business-roadmap">Business roadmap</h2> <p>The health of Sourcehut as a business is also my responsibility. Providing the hosted service is not free, and getting myself paid enough to keep food on the table is important for the development and health of the project as a whole. This basically involves lots of spreadsheets, tracking the income and expenses of the business, and making projections for the future. The monitoring system maintained by the operations work is also put to use for BI (business intelligence) reporting and monitoring.</p> <p>I basically maintain three projections: pessimistic, realistic, and optimistic. A rough approximation of how these are done is: pessimistic projections assume that no one signs up for new subscriptions, monthly subscriptions continue paying out, and yearly subscriptions don&rsquo;t. Realistic projections amortize yearly subscriptions over a year, assume no one cancels, but also assumes no growth. Optimistic projections expect the current rates of growth to continue. Most of our long-term planning is based on the pessimistic projections. These models are going to be updated soon as we start to get data on how many users cancel their subscription when the first yearly renewals come up this month.</p> <p>This work also involves dealing with taxes, regulatory compliance, making sure contractors are paid on time, and so on. Boring stuff, but it eats up a lot of time. Additionally, marketing falls under this umbrella, which mainly takes the form of posts on this blog and showing up when people talk about us online to answer questions. I&rsquo;ve tried asking happy users to blog about their experiences, but most people don&rsquo;t have a blog or are shy about writing, so there&rsquo;s some <a href="https://drewdevault.com/make-a-blog">yak shaving to be done first</a>.</p> <p>The main business goal at first was profitability, which has been achieved. Additional goals are to generate a revenue stream which can continue to support investment in new hardware, sponsoring free accounts for less fortunate users, marketing and outreach efforts, and sponsoring free software developers to work on self-directed projects. All of these goals are proceeding nicely.</p> <h2 id="stability-roadmap">Stability roadmap</h2> <p>How do these development phases play into the external stability presented by the service? Thus far, all of this development has been considered &ldquo;alpha&rdquo;. There are two additional phases: beta and production. The scope and completion criteria of each phase in the stability roadmap is informed by the progress in each other roadmap.</p> <p>For example, some of the development tasks blocking the graduation from alpha to beta include:</p> <ul> <li>User groups (for organizations managing many accounts or projects)</li> <li>Completely web-driven patchset submission and code review</li> <li>A centralized, indexed project hub which allows you to link a project&rsquo;s git/hg repos, bug trackers, mailing lists, and so on under a single top-level &ldquo;project&rdquo;</li> <li>Data ownership, i.e. self-service data import and export tools for all services</li> </ul> <p>In operations, an overhauled alarming system is a blocker for the beta, and high availability is a blocker for production. Confidence in our data integrity and security systems is a beta requirement, and has already been achieved.</p> <p>On the business side, a beta task was to achieve sustainability - that is, to make a profit - which was achieved in Q1 2019. A business which is losing money cannot be considered stable, after all. An outstanding business task which still holds up the beta is establishing the final pricing model for the beta and into the future.</p> <h1 id="status-update">Status update</h1> <p>Phew! What a long article. Thanks to everyone for helping out during the alpha, I really appreciate your support. Since the last update, we have another 825 users to welcome to the platform, bringing our grand total up to 11,364. 1,320 of you have chosen to pay for your alpha account, which I am deeply grateful for. Thank you, everyone! Let&rsquo;s get to the updates for this month.</p> <h2 id="general-updates">General updates</h2> <p>Thanks to Eli Schwartz&rsquo;s help, the Arch Linux package repo saw some improvements this month, and Luca Weiss pitched in to fix some outdated database migration scripts. Thanks guys!</p> <h2 id="gitsrht">git.sr.ht</h2> <p>I&rsquo;ve been working on performance improvements for git over SSH again. An earlier attempt was an abject failure - I had moved some logic into the web app and accessed it over an internal API, under the rationale that the web app had already spent the Python VM and SQLAlchemy setup time. In fact what really happened is that git operations - which happen all the time - started to pin the web workers, because Python can&rsquo;t into async. The result is that the entire stack slowed down dramatically. I rolled a nat&rsquo; 1 on that one.</p> <p>The new solution is way, way better. I rewrote two pieces of the pipeline in Go and overhauled the SQL queries, and now the time-to-/usr/bin/git is significantly reduced, often less than a second. Prior to the disastrous change, it could be as much as 10 seconds, and post disastrous change it was as much as 45, with the web app being slowed to a similar crawl. With this approach, git operations are fast and the web app is buttery smooth. The last piece to improve on is the post-update hook. You&rsquo;ll notice the slowness there, since git will quickly show its push output, then stop again while we run the post-update. I hope to improve this soon.</p> <p>I know that the git-over-SSH performance has been disappointing for a while, and I&rsquo;m sorry. The pipeline here is a complex machine with lots of moving parts, and all of them are slow. A comprehensive solution requires a lot of overhauling.</p> <p>Third-party contributions to git.sr.ht have also been coming in recently, with Ian Moody making improvements to the diff view (for hg.sr.ht, too), and Honza Porkorny switching our tree views to a monospaced font. I&rsquo;ve also made a number of bug fixes to the new patchset preparation UI.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>I&rsquo;ve implemented half of the necessary steps for todo.sr.ht to meet its data ownership goals, by implementing a data export tool. There is some interesting novelty here that merits some attention. The export prepares a gzipped JSON dump of all of your tracker&rsquo;s tickets and events, and is more or less just a shortcut to the API. However, certain information - usernames, comment text, and such - are signed with SourceHut&rsquo;s webhook signing key. The idea is that if you re-import these dumps later, we can verify that anything our users have said on the tracker has not been tampered with, and confidently show their username next to their comments. Additionally, third-party Sourcehut instances which trust our word upstream can check these signatures against our key and be confident that those are authentic comments authored by Sourcehut users.</p> <p>However, this will only be useful when the data import side of this work is completed, which is still to come. In other news, Ivan Habunek has written a UI for editing labels, and added URL parameters for auto-filling the title and description for new tickets, which is useful, for example, to provide links to file tickets pre-populated with stack traces.</p> <h2 id="dispatchsrht">dispatch.sr.ht</h2> <p>dispatch.sr.ht can now build GitLab commits! I wanted to add merge requests as well, but it&rsquo;s blocked by <a href="https://gitlab.com/gitlab-org/gitlab/issues/16491">this GitLab bug</a>. If/when this issue is addressed, running builds.sr.ht CI for GitLab merge requests will be possible as well. This is currently available for gitlab.com and gitlab.freedesktop.org - if you want me to set it up for your GitLab instance, please send me an email.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>Just some small updates: I have added URLs for obtaining a user&rsquo;s SSH and PGP public keys. Just visit meta.sr.ht/~username.keys or ~username.pgp. There have also been some improvements to the billing pages, which is especially important as the first yearly payments will start renewing soon.</p> <h2 id="pastesrht">paste.sr.ht</h2> <p>Thanks to Mykyta Holubakha&rsquo;s hard work, pastes on paste.sr.ht can now be deleted! This was non-trivial because we de-duplicate paste contents in the database. Thanks Mykyta! We&rsquo;re hoping to see support for editing pastes coming soon as well.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>Some mundane image updates:</p> <ul> <li>freebsd/12.x builds are now using FreeBSD 12.1</li> <li>Fedora images have been improved and updated</li> <li>NixOS images have been improved and updated</li> </ul> <p>Additionally, OpenBSD 6.6 support is right around the corner. Thanks to our hardworking build image maintainers for keeping up with these releases!</p> <h2 id="namessrht">names.sr.ht</h2> <p>Progress has been made since this was teased in October. That&rsquo;s all I&rsquo;ve got to say :)</p> Our model is customers first, investors never https://sourcehut.org/blog/2019-10-23-srht-puts-users-first/ Wed, 23 Oct 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-10-23-srht-puts-users-first/ <p>SourceHut was built by veterans of the Internet, who have watched the turbulent lifecycle of Internet-based businesses coming into popularity and fading into obscurity time and again. Most large online businesses these days are for-profit companies funded with venture capital, and that leads to a certain set of incentives. It was no surprise to us, accordingly, to receive this email from GitLab today:</p> <blockquote> <p>We have launched important updates to our Terms of Service surrounding our use of telemetry services. Starting with GitLab 12.4, existing customers who use our proprietary products (that is, GitLab.com and the Enterprise Edition of our self-managed offerings) may notice additional Javascript snippets that will interact with GitLab and/or third-party SaaS telemetry service (such as Pendo).</p> <p>For GitLab.com users: as we roll out this update you will be prompted to accept our new Terms of Service. Until the new Terms are accepted access to the web interface and API will be blocked. So, for users who have integrations with our API this will cause a brief pause in service via our API until the terms have been accepted by signing in to the web interface.</p> <p>For Self-managed users: GitLab Core will continue to be free software with no changes. If you want to install your own instance of GitLab without the proprietary software being introduced as a result of this change, GitLab Community Edition (CE) remains a great option. It is licensed under the <a href="https://en.wikipedia.org/wiki/MIT_License">MIT license</a> and will contain no proprietary software. Many open source software projects use GitLab CE for their SCM and CI needs. Again, there will be no changes to GitLab CE.</p> </blockquote> <p>You can read the whole email <a href="https://paste.sr.ht/~sircmpwn/23e31a29f427066ef261b2ffa7fd9bf46530d904">here</a>, or in your inbox if you have a GitLab account. The summary is that GitLab will soon:</p> <ul> <li>Disable web and API access until users consent to be tracked</li> <li>Add third-party telemetry to their hosted and enterprise offerings</li> <li>With obfuscated, third-party, proprietary JavaScript</li> </ul> <p>This can naturally be frustrating to privacy-concious users of their service, and to free software enthusiasts alike. This follows closely on the news that GitLab <a href="https://gitlab.com/gitlab-com/www-gitlab-com/commit/b5a35716deb4f63299a23a40510475f5503c11c4">updated official policy</a> to state that they will do business with those who don&rsquo;t share their values, which many see as a response to GitHub taking fire for accepting <a href="https://en.wikipedia.org/wiki/U.S._Immigration_and_Customs_Enforcement">ICE</a> contracts a few days prior. These kinds of changes are not implemented with the user in mind - these decisions are more easily explained by following the money. GitLab is trying to figure out how it can turn a profit that can support its <a href="https://www.forbes.com/sites/alexkonrad/2019/09/17/gitlab-doubles-valuation-to-nearly-3-billion/#79593f2c1794">$2.75B valuation</a>. The nature of this business model leaves businesses like GitLab indebted to investors, who&rsquo;ve sunk millions into the business and demand a return. An individual user&rsquo;s investment is comparatively meaningless, and the incentives this creates easily leads to compromises like the ones we&rsquo;re seeing in GitLab recently.</p> <p>I<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> have written about the up-and-down lifecycle of Internet businesses <a href="https://drewdevault.com/2014/10/10/The-profitability-of-online-services.html">as early as 2014</a>, when I noticed a trend among image hosting websites to make decisions which increasingly favored their business at the expense of their users. This culminated in the failure of an early business venture of mine, MediaCrush, when we chose to close the service instead of making these compromises. In the years since I&rsquo;ve found that this problem generalizes across the entire industry and beyond. When designing the business model for SourceHut, I vowed that this would never be our fate.</p> <p>SourceHut has never accepted any outside funding, it&rsquo;s completely bootstrapped. I started the business while working a full-time job and built it in my spare time over the course of two years. Next month will mark the third anniversary of the project and the end of the first year of public alpha. Today, it&rsquo;s a profitable business and we&rsquo;ve just brought on <a href="https://sourcehut.org/blog/2019-10-15-whats-cooking-october-2019/">our first full-time sponsored free software developer</a>. Some people have complained that paying for their account on SourceHut is a deal breaker. But, consider that the incentives that this approach creates hold us accountable <em>only</em> to the users. When you let venture capitalists foot your bill, you also give them power over you. And in any case, free SourceHut accounts are available by request to anyone with extenuating circumstances<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</p> <p>Thanks to this incentive model, SourceHut can easily skip anti-features:</p> <ul> <li>We don&rsquo;t send your data to third parties<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></li> <li>We have no tracking whatsoever</li> <li>Everything works without JavaScript anyway</li> <li>We don&rsquo;t use opt-out marketing emails</li> <li>There are no advertisements in the UI</li> <li>The hosted code is the same as the open source code</li> <li>No one can strong-arm us into taking on unethical business partners</li> </ul> <p>Since we get all of our income directly from the users, we don&rsquo;t have to worry about finding other ways to monetize you. To me that seems like a pretty good business model, even if it&rsquo;s never going to be a &ldquo;unicorn&rdquo;.</p> <hr> <blockquote> <p><strong>UPDATE</strong>: Thanks for the feedback. There were many more concerns than we expected. We’re going to process the feedback and rethink our plan. We will not activate product usage tracking on GitLab.com or GitLab self-managed for now. We&rsquo;ll make sure to communicate in advance on our blog when we do have a new plan.</p> </blockquote> <p>via <a href="https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/33289/diffs">gitlab.com/www-gitlab-com!33289</a></p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>Hi, I&rsquo;m Drew DeVault, founder of SourceHut and your friendly neighborhood sysadmin.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:2"> <p>Technically, you don&rsquo;t have to pay at all during the alpha.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> <li id="fn:3"> <p>The exception is your billing information, but we don&rsquo;t have much of a choice about that.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> Sourcehut Q3 2019 Financial report https://sourcehut.org/blog/2019-10-21-sourcehut-q3-2019-financial-report/ Mon, 21 Oct 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-10-21-sourcehut-q3-2019-financial-report/ <p>In summary, Sourcehut is financially healthy, with an operating monthly profit of about $1,038. Slowed growth in Q2 picked back up in Q3, to levels similar to Q1. Though perpetual growth is not a goal of Sourcehut, growth does help us accomplish our goals. One of these goals is to sponsor members of the open-source community to work on self-directed projects - a goal which was met for Q4, when Simon Ser will be joining us. My goals for future growth are:</p> <ul> <li>Investing in additional hardware and resources</li> <li>Marketing &amp; outreach</li> <li>Investing in the broader open-source ecosystem</li> </ul> <p>Thank you for your support in the alpha. I&rsquo;m looking forward to continuing to serve you.</p> <p>Disclaimer: this report is a summarized approximation of Sourcehut&rsquo;s financials, and is not used for tax purposes.</p> <h2 id="revenue-sources">Revenue sources</h2> <p>Sourcehut receives revenue from paid user subscriptions. During Q1, we processed 1,134 invoices. The invoices paid break down as:</p> <pre><code>612 $2 (paid monthly) 282 $5 (paid monthly) 65 $10 (paid monthly) 121 $2 (paid yearly) 43 $5 (paid yearly) 11 $10 (paid yearly) </code></pre> <p>The total gross revenue during this period was $9,172.00, which after transaction fees comes out to $8,511.83. This is an improvement over Q2, but falls just short of Q1 revenue. In Q3, 1,650 new users registered accounts, of which 204 (12%) have paid for their account. As of the end of Q3, there were 10,331 registered users in total, of which 1,272 (12.3%) have paid subscriptions.</p> <p>At time of writing (2 weeks into Q4), the breakdown of subscription types is as follows:</p> <pre><code>223 $2 (paid monthly) 104 $5 (paid monthly) 26 $10 (paid monthly) 582 $2 (paid yearly) 174 $5 (paid yearly) 62 $10 (paid yearly) </code></pre> <p>The monthly revenue from these subscriptions (with annual subscriptions realized over 12 months) is approximately $3,307, after transaction fees. This is a $734 increase in monthly revenue compared to Q2.</p> <p>Sourcehut has $10,748 in the bank at the time of writing (2019-10-21).</p> <p>Breakdown of Q3 expenses:</p> <pre><code>$1950 Philadelphia datacenter lease (inc. network, power, etc) $1693 New server equipment $ 360 Contractor payments (artwork) $ 129 San Francisco datacenter lease (inc. network, power, etc) $ 107 Misc $ 95 Research expenses (names.sr.ht) </code></pre> <p>Payroll:</p> <pre><code> $1,500.00 Drew DeVault (CEO) +$ 179.07 Employer taxes &amp; processing fees </code></pre> <p>Going into Q4, our monthly expenses are expected to be:</p> <pre><code>$1500/mo Payroll (approximate) $640.00/mo Philadelphia datacenter lease $129/qtr San Francisco datacenter lease </code></pre> <p>Starting in Q4, Sourcehut will be sponsoring the work of free software developer Simon Ser, which is being recorded under Payroll for these quarterly financial reports. To protect his privacy, I have adjusted my personal salary and summed payroll into a single figure. This figure will continue to be opaque until a few more hires are made, after which I will resume disclosure of my personal salary.</p> <p>The closure of Q4 will mark one year of Sourcehut&rsquo;s public alpha. Accordingly, yearly subscriptions will be renewing for the first time. What fraction of these subscriptions will bounce, be cancelled, or refunded will have a significant impact our financial planning, and is the biggest financial unknown we face leading into Q4. We&rsquo;re planning a light marketing drive to remind our subscribers of what we&rsquo;ve accomplished in 2019, and what we&rsquo;re planning going into 2020.</p> What's cooking on Sourcehut? October 2019 https://sourcehut.org/blog/2019-10-15-whats-cooking-october-2019/ Tue, 15 Oct 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-10-15-whats-cooking-october-2019/ <p>I&rsquo;m more excited to give today&rsquo;s status update than any other so far. To get the necssary bits out of the way: this month, 368 users have joined the community, bringing our total to 10,539<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. Welcome!</p> <h2 id="general-news-simon-ser-joins-us">General news: Simon Ser joins us</h2> <p>I&rsquo;m very excited to announce that <a href="https://emersion.fr/">Simon Ser</a> will be joining Sourcehut. His role will be interesting, and representative of my vision for Sourcehut in the long-term. Simon&rsquo;s responsibilities are to simply continue working on self-directed free software projects. I chose to work with him because he&rsquo;s already a talented generalist and motivated member of the free software community. He&rsquo;s written more about his specific plans in <a href="https://emersion.fr/blog/2019/working-full-time-on-open-source/">his own blog post</a>, but with our support he&rsquo;ll be working on projects like <a href="https://mrsh.sh/">mrsh</a>, <a href="https://wayland.emersion.fr/">Wayland</a>, and the maintenance of <a href="https://github.com/emersion?utf8=%E2%9C%93&amp;tab=repositories&amp;q=&amp;type=&amp;language=go">large swaths of Golang&rsquo;s email landscape</a>.</p> <p>Some of Simon&rsquo;s work directly benefits Sourcehut, but the goal of sponsoring his work is to help populate the open source ecosystem as a whole with motivated, financially stable developers with the freedom to work at their own direction. If you&rsquo;ve been following the <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss?search=financial+report">financial reports</a>, this kind of work is what I plan on spending Sourcehut&rsquo;s profits on: directly elevating the free and open source software community.</p> <p>Additionally, thanks to Denis Laxalde&rsquo;s help, Sourcehut packages are now available for Debian from our <a href="https://man.sr.ht/packages.md#debian">new Debian repository</a>. Thanks Denis!</p> <h2 id="gitsrht-web-based-patchsets">git.sr.ht: web-based patchsets</h2> <p>Many of you recall one of the original promises of Sourcehut: web-driven tooling built on top of an email-driven workflow. This is part of the third broad phase of Sourcehut development. These three phases are: (1) build a bunch of self-contained tools which represent the primitives of a development system; (2) extend them with comprehensive APIs and webhooks; (3) teach them to talk to each other. This design takes longer to bear fruit, but the result is worth it. However, our wait is starting to come to a close: this week, I implemented patchset preparation on the web.</p> <video src="https://sr.ht/_fUk.webm" controls muted> Your web browser does not support the webm video codec. Please consider using web browsers that support free and open standards. </video> <p>This is now live on git.sr.ht! Please give it a shot and let me know your thoughts. Progress is being made on the other end of this workflow as well - see the lists.sr.ht updates later on. In other git.sr.ht news, some long-requested features like release blobs and git-lfs are showing signs of life. This month, a shiny new 64TB NAS was provisioned and installed in our datacenter, and will be the backbone upon which many of these features are implemented.</p> <h2 id="listssrht">lists.sr.ht</h2> <p>I have been working on lists.sr.ht indirectly recently, in the form of improvements to <a href="https://github.com/libgit2/libgit2/pulls/ddevault">libgit2</a> and <a href="https://github.com/libgit2/pygit2/pulls?q=is%3Apr+author%3Addevault+is%3Aclosed">pygit2</a> upstream. The idea is to expose libgit2&rsquo;s pluggable backends to pygit2, so that I can create a <code>pygit2.Repository</code> which is backed by git.sr.ht via the git.sr.ht API.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>NetBSD folks have been helping me work through the issues, but it&rsquo;s slow going. If anyone wants to have a go at it, <a href="https://yukari.sr.ht/netbsd.qcow2.xz">download this image</a> and see if you can&rsquo;t figure out how to make it expand the partitions and filesystem to fill available space on first boot. It&rsquo;s generated with <a href="https://git.sr.ht/~sircmpwn/builds.sr.ht/tree/master/images/netbsd">these scripts</a> on a NetBSD host.</p> <p>That same NAS I mentioned in the git.sr.ht update, by the way, is going to be used for build artifacts soon, and likely for build caches as well, which will speed up many classes of builds. Additionally, a POWER9 server has been provisioned and installed in the DC, which I&rsquo;m preparing to eventually become a ppc64le builder. I&rsquo;m looking forward to seeing both in action!</p> <h2 id="pastesrht">paste.sr.ht</h2> <p><a href="https://paste.sr.ht">paste.sr.ht</a> received some polish this month thanks to the hard work of Mykyta Holubakha. A public index of your pastes, access controls, and soon paste deletion are all being added to the platform.</p> <h2 id="namessrht">names.sr.ht</h2> <p><img src="https://sr.ht/_yhw.png" alt=""></p> <div class="footnotes" role="doc-endnotes"> <hr> <ol> <li id="fn:1"> <p>Note: I&rsquo;ve changed the way the total users are calculated this month. Previously, the number included people who signed up but never confirmed their registration via email.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> </li> </ol> </div> What's cooking on Sourcehut? September 2019 https://sourcehut.org/blog/2019-09-15-whats-cooking-on-sourcehut-september-2019/ Sun, 15 Sep 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-09-15-whats-cooking-on-sourcehut-september-2019/ <p>Another month of progress in the Sourcehut alpha! This month, we reached the big 10,000 user mark, and kept going: at the time of writing, there are 10,649 users. To the 938 of you who&rsquo;ve joined us since the August update, welcome! I&rsquo;m sure many of you have joined us after abandoning the <a href="https://sourcehut.org/blog/2019-08-21-sourcehut-welcomes-bitbucket-refugees/">sinking Bitbucket ship</a>, and if so I hope you&rsquo;ve found Sourcehut to your liking. If you have any questions or feedback, I can be reached at <a href="mailto:[email protected]">[email protected]</a>. And a special thanks to the 1,093 users who have paid for their alpha accounts, which for the first time represents more than 10% of all registered users.</p> <h2 id="general-news">General news</h2> <p>First, I&rsquo;ve redesigned <a href="https://sourcehut.org">sourcehut.org</a> to be a little bit more attractive and lend an air of professionalism to Sourcehut. I&rsquo;ve also added to it a blog, which has a greater scope than sr.ht-announce. I will be cross-posting these monthly &ldquo;what&rsquo;s cooking&rdquo; updates there as well, for anyone who prefers to read them on the web or keep updated via RSS. Though the design of sourcehut.org is a bit more flamboyant than sr.ht in general, I&rsquo;ve made a few conservative improvements to the layout of sr.ht pages, notably centering everything and bumping the base font size up to the system default.</p> <p>I would also like to thank Denis Laxalde for his hard work lately, thanks to which we&rsquo;re starting to see a Debian repository come into being for sysadmins who want to run Sourcehut on Debian hosts. I hope we&rsquo;ll see that finished up soon!</p> <h2 id="listssrht">lists.sr.ht</h2> <p>No notable developments this month, but there has been some planning I&rsquo;d like to share with you. I&rsquo;ve been working this week on improvements to <a href="https://github.com/libgit2/libgit2">libgit2</a> and <a href="https://github.com/libgit2/pygit2">pygit2</a> with the aim of improving integration between lists.sr.ht and git.sr.ht (and later hg.sr.ht, but that&rsquo;s a more difficult problem for technical reasons). To address goals like continuous integration for patches sent to the mailing list, expanding the diff context beyond what&rsquo;s included in the patch, and a little blue &ldquo;submit&rdquo; button to apply patches from the web, I basically intend to create a libgit2 backend which allows you to create a <code>Repository</code> object which, instead of being backed by a git repo on disk, is backed by the git.sr.ht API.</p> <p>I also intend to add a similar backend for Github and Gitlab, if possible, and let you use lists.sr.ht to track patches against projects which aren&rsquo;t hosted on Sourcehut. There&rsquo;ll probably be lots of use-cases for this that I haven&rsquo;t thought of! One interesting thing you&rsquo;d be able to do with this is have a working git repository on your local machine which doesn&rsquo;t have a .git directory, but instead does all of its operations remotely against a git.sr.ht repository - albeit very slowly. I&rsquo;m not sure why you&rsquo;d ever want to do this. Interesting nonetheless!</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Some minor bug fixes and improvements landed this month, but the most interesting addition is that of participating via email <em>without</em> an account. You can now send an email to the tracker or to a ticket to submit or comment on tickets without a Sourcehut account. If you are the operator of a bug tracker on the service, you can configure the permissions for such users by changing the &ldquo;anonymous&rdquo; permissions on your tracker. In the near(ish) future, I also plan on extending ACLs so you can give individuals more or less permission by email, which will make non-account holders first-class citizens on todo.sr.ht, more or less.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>I wrote a <a href="https://sourcehut.org/blog/2019-09-12-sourcehut-makes-bsd-software-better/">blog post</a> about how builds.sr.ht is being used by lots of software to improve their BSD support, give it a read if you&rsquo;re interested. On a related note, I&rsquo;ve received some offers for aid in finishing our NetBSD image, so hopefully we&rsquo;ll see support for that soon.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>Arch Linux developer Eli Schwartz has put some effort into making busybox&rsquo;s gzip output deterministic and matching GNU&rsquo;s gzip, which makes our source tarball downloads from git.sr.ht consistently hash with ourselves and with other git hosts. Thanks Eli!</p> <h2 id="mansrht">man.sr.ht</h2> <p>I redesigned it, now it doesn&rsquo;t look like crap. Hooray! As part of this work, you can now explicitly enable or disable the generation of a table of contents for any page by <a href="https://man.sr.ht/man.sr.ht/#frontmatter">updating its frontmatter</a>.</p> Sourcehut makes BSD software better https://sourcehut.org/blog/2019-09-12-sourcehut-makes-bsd-software-better/ Wed, 11 Sep 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-09-12-sourcehut-makes-bsd-software-better/ <p>Every day, Sourcehut runs continuous integration for FreeBSD and OpenBSD for dozens of projects, and believe it or not, some of them don&rsquo;t even use Sourcehut for distribution! Improving the BSD software ecosystem is important to us, and as such our platform is designed to embrace the environment around it, rather than building a new walled garden. This makes it easy for existing software projects to plug into our CI infastructure, and many BSD projects take advantage of this to improve their software.</p> <p>Some of this software is foundational stuff, and their improvements trickle down to the entire BSD ecosystem. Let&rsquo;s highlight a few great projects that take advantage of our BSD offerings.</p> <h1 id="programming-languages-janet-nim-zig">Programming languages: Janet, Nim, Zig</h1> <p>Several programming languages use Sourcehut to run BSD testing. The <a href="https://janet-lang.org/">Janet</a> language uses Sourcehut to test both <a href="https://builds.sr.ht/~bakpakin/janet/.freebsd.yaml">FreeBSD</a> and <a href="https://builds.sr.ht/~bakpakin/janet/.openbsd.yaml">OpenBSD</a>, and fast - each build takes only about a minute! The newest language to join us is <a href="https://nim-lang.org/">Nim</a>, which now uses builds.sr.ht to make sure every Github pull request works correctly on FreeBSD and OpenBSD. The <a href="https://ziglang.org/">Zig</a> project, long time friends of Sourcehut, have also been using builds.sr.ht to test their FreeBSD support, and they host their mailing lists with us, too.</p> <p>The stability of programming languages is especially important, as bugs in the compiler or implementation will affect all software compiled with it. Thanks for using Sourcehut to keep your BSD support in good shape, guys!</p> <h1 id="end-user-software-neovim-mutt">End-user software: Neovim, mutt</h1> <p>End-user software gets in on the fun, too, which puts more stable BSD software closer to your fingertips. The <a href="https://neovim.io/">Neovim</a> project, a fast moving and modern fork of the venerable Vim text editor, uses builds.sr.ht for OpenBSD testing, and working on using it to help fix <a href="https://github.com/neovim/neovim/pull/10907">bugs in their FreeBSD port</a>. The similarly venerable <a href="http://mutt.org">mutt</a> email client has also been experimenting with Sourcehut recently. They&rsquo;re using builds.sr.ht to make sure mutt compiles on FreeBSD, Alpine Linux, and Debian, and they&rsquo;re trying out lists.sr.ht mailing lists, too.</p> <h1 id="display-servers-wlroots-sway">Display servers: wlroots, sway</h1> <p>One of my own projects, <a href="https://github.com/swaywm/wlroots">wlroots</a>, was one of the first adopters of Sourcehut, to no surprise. We were also early adopters of FreeBSD support, and now we use it to test that <a href="https://github.com/swaywm/wlroots/wiki/Projects-which-use-wlroots">dozens of Wayland compositors</a> work well on the platform. Several of these test themselves further down the stack on FreeBSD as well, such as my own <a href="https://swaywm.org">sway</a> project, and the <a href="https://github.com/Hjdskes/cage">cage</a> project, and more projects still are using Sourcehut to test other operating systems as well.</p> <h1 id="small-projects-too">Small projects, too!</h1> <p>Lots of smaller projects have been taking advantage of Sourcehut&rsquo;s BSD tools, too, to make sure they&rsquo;re set up right on for our Berkley friends from the start. Simon Ser&rsquo;s <a href="https://mrsh.sh/">mrsh</a> shell tests on <a href="https://builds.sr.ht/~emersion/mrsh">FreeBSD, Arch Linux, and Alpine Linux</a>. Michael Forney&rsquo;s <a href="https://github.com/michaelforney/samurai">samurai</a> project uses Sourcehut builds to test <a href="https://builds.sr.ht/~mcf/samurai">four operating systems, including Free and OpenBSD!</a></p> <h1 id="and-yours">And yours?</h1> <p>Want to try it yourself? Just set your <a href="https://man.sr.ht/builds.sr.ht/manifest.md">build manifest</a>&rsquo;s image to <code>freebsd/latest</code> or <code>openbsd/latest</code> and drop it into the <a href="https://builds.sr.ht/submit">submit page</a> to give it a test drive - no need to push any half-baked test commits until it&rsquo;s done. Check out the <a href="https://man.sr.ht/builds.sr.ht/compatibility.md">compatibility page</a> for details on builds.sr.ht support for *BSD and other operating systems, and check out <a href="https://dispatch.sr.ht">dispatch.sr.ht</a> to add BSD CI to your Github projects.</p> <p><strong>Hey!</strong> Are you a NetBSD expert? We need some help to finish up NetBSD support on builds.sr.ht. <a href="mailto:~sircmpwn/[email protected]">Get in touch?</a></p> Sourcehut welcomes Bitbucket refugees https://sourcehut.org/blog/2019-08-21-sourcehut-welcomes-bitbucket-refugees/ Wed, 21 Aug 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-08-21-sourcehut-welcomes-bitbucket-refugees/ <p>Atlassian <a href="https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket">announced on Wednesday</a> that Bitbucket is shuttering its Mercurial offering.</p> <p>For those looking for a new host, Sourcehut may be a good choice for you. Unlike its closed-source competitors, Sourcehut is <a href="https://git.sr.ht/~sircmpwn/?search=sr.ht">100% open source software</a>, and thanks to the Mercurial community (especially Ludovic Chabant), Hg support on Sourcehut is strong and will remain so for as long as the Hg community is committed to it.</p> <p>Bitbucket users may find our workflow different from what they&rsquo;re used to, but it&rsquo;s different for good reasons. Give it an shot and ask for help if you need it. We&rsquo;ve prepared <a href="https://hg.sr.ht/%7Esircmpwn/invertbucket">a migration tool</a> which will import your Bitbucket repos and issues.</p> What's cooking on Sourcehut? August 2019 https://sourcehut.org/blog/2019-08-15-whats-cooking-on-sourcehut-august-2019/ Thu, 15 Aug 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-08-15-whats-cooking-on-sourcehut-august-2019/ <p>Thank you for continuing to support Sourcehut during the alpha period! I have loads of exiting developments to share with you today. Let&rsquo;s welcome our newest 369 users to the platform, which now totals 9,711 in number.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>I&rsquo;m happy to announce lots of cool features for builds.sr.ht this month. First, the VMs for failed builds are now being kept alive for 10 minutes after the completion of your build, and you can SSH into them to examine the failure more closely (if you do so, the 10 minute deadline is extended to the original time limit for your build).</p> <p><img src="https://sr.ht/thL-.png" alt="Screenshot of a failed build prompting the user to SSH into the VM"></p> <p>You can also SSH into build jobs just if you&rsquo;d find it useful. Need an OpenBSD shell to try something out?</p> <pre><code>image: openbsd/latest shell: true </code></pre> <p>Paste that into builds.sr.ht/submit and you&rsquo;ll get your SSH connection details a few moments later. You can also still add all of your tasks, packages, repos, and such; perhaps cloning your dotfiles repo and installing your favorite text editor.</p> <p>SSH access is still in its early stages, but development is well underway on features like submitting build manifests over SSH, e.g.</p> <pre><code>ssh [email protected] submit &lt; .build.yml </code></pre> <p>as well as <code>tail -f</code>-ing build logs in your terminal.</p> <p>Additionally, I have progress to announce on experimental multi-arch support. arm64 is now available for Debian images, and is being kept up-to-date with automated builds. I&rsquo;ve also made progress on ppc64el support using a similar approach. Currently this is done with software emulation via qemu, but in the next couple of months, I expect to have ppc64le hardware builds available.</p> <p>The <code>ubuntu/latest</code> image now points to Ubuntu Disco and <code>freebsd/latest</code> to FreeBSD 11.3, following their respective upstream releases.</p> <h2 id="mansrht">man.sr.ht</h2> <p>Thanks to the hard work of Ryan Chan and after a complex migration process, a major update to man.sr.ht has been deployed. No longer are the backing git repos stored with man.sr.ht itself - they&rsquo;ve now been transferred to git.sr.ht repositories and man.sr.ht uses webhooks and the git.sr.ht API to fetch content from them. This means you can now browse your wikis on git.sr.ht using the fully featured git repository browsing interface, but you can also put your wikis directly into the git repos they document under a &ldquo;wiki&rdquo; branch or something similar. Thanks to Ryan for all your hard work!</p> <h2 id="gitsrht">git.sr.ht</h2> <p>A problem which has plagued git.sr.ht for some time now is slow performance on git operations over SSH. Though there&rsquo;s still many improvements to be made, I spent some time this month whetting down the bottlenecks and, as a result, git pull is 5x faster and git push is 2x faster. Thanks to Preston Carpenter for helping to identify some of the bottlenecks! The remaining bottlenecks are well-understood and I expect to make further improvements soon. Anyone interested in helping on this should reach out on IRC - there&rsquo;s a lot of cool stuff involved.</p> <p>Additionally, following the announcement of code annotations for git.sr.ht, several projects have grown which add support for their favorite programming languages:</p> <ul> <li><a href="https://git.sr.ht/~emersion/annotatesh">POSIX shell</a></li> <li><a href="https://git.sr.ht/~ihabunek/annotatepy">Python</a></li> <li><a href="https://git.sr.ht/~wezm/annotate-rust">Rust</a></li> </ul> <p>If you&rsquo;re working on one yourself, please let me know!</p> <h2 id="listssrht">lists.sr.ht</h2> <p>Because Sourcehut requires the use of plaintext email, many email clients will run into this limitation quickly with their default configuration. Previously, you&rsquo;d get a very user-unfriendly bounce message from postfix which doesn&rsquo;t give you much help towards fixing this problem. Instead, the bounces are now sent from lists.sr.ht itself and replace the mail server diagnostic info with a friendlier description of the problem and resources to address it - namely, <a href="https://useplaintext.email">useplaintext.email</a>.</p> <p>Other error messages which can be returned by lists.sr.ht have received similar treatment.</p> <h2 id="interesting-projects-using-sourcehut">Interesting projects using Sourcehut</h2> <p>The <a href="http://mutt.org/">mutt email client</a> is experimenting with a sr.ht git mirror and mailing list, as well as builds.sr.ht CI.</p> <p><a href="https://gioui.org">Gio</a> is an immediate mode GUI toolkit for Golang.</p> <p>Thanks for using Sourcehut, guys! Be sure to let me know about your new projects - post them to the <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss">sr.ht-discuss</a> list.</p> What's cooking on Sourcehut? July 2019 https://sourcehut.org/blog/2019-07-15-whats-cooking-on-sourcehut-july-2019/ Mon, 15 Jul 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-07-15-whats-cooking-on-sourcehut-july-2019/ <p>Hello again, and thank you for your support during SourceHut&rsquo;s alpha! This month, our ranks have grown by 352 users, bringing our total company to 9,342 users. The big 10K looms over the horizon! I have some very cool developments to share with you this month.</p> <h2 id="gitsrht">git.sr.ht</h2> <p>The first and perhaps most exciting development is the availability of code annotations on git.sr.ht. This feature allows you to upload a list of annotations to your repo, which can link from function references to their definition (and vice versa), or link to ticket IDs referenced in comments, or anything else you can dream up. The system is quite flexible and should grow easily to support any number of cool use-cases you can dream up.</p> <p>I&rsquo;ve written <a href="https://drewdevault.com/2019/07/08/Announcing-annotations-for-sourcehut.html">a longer article</a> on my blog which goes into detail on the implementation. If you&rsquo;d just like to get a quick feel for the feature, here are a few cool annotated repos for you to browse:</p> <ul> <li><a href="https://git.sr.ht/~sircmpwn/scdoc/tree/master/src/main.c">scdoc</a>: a man page generator (C)</li> <li><a href="https://git.sr.ht/~sircmpwn/aerc/tree/master/widgets/msgviewer.go">aerc</a>: a TUI email client (Go)</li> <li><a href="https://git.sr.ht/~mcf/cproc/tree/master/scan.c">cproc</a>: a C compiler frontend (C)</li> </ul> <p><a href="https://man.sr.ht/git.sr.ht/annotations.md">Documentation for annotations can be read here</a>. First-party annotators are available for C and Go, and the community is working on annotators for <a href="https://git.sr.ht/~wezm/annotate-rust">Rust</a> and <a href="https://git.sr.ht/~ihabunek/annotatepy">Python</a> as well. I hope to extend this feature to hg.sr.ht soon as well. If you write an annotator for your favorite programming language, please let us know on the sr.ht-discuss mailing list!</p> <h2 id="todosrht">todo.sr.ht</h2> <p>Ivan Habunek has come along with another great patchset this month, this time adding per-user access control lists to your todo.sr.ht trackers. This is similar in implementation to the corresponding lists.sr.ht feature, and can be used to set up private ticket trackers with your collaborators, post-only security trackers, banning troublesome users, and more. I&rsquo;ve also added support for adding and removing labels over email (by replying to the notification with &ldquo;!label example&rdquo; on the last line), and Paul Wise has improved our notification&rsquo;s email signatures to be RFC 3676-compliant. Thanks for the patches, folks!</p> <h2 id="listssrht">lists.sr.ht</h2> <p>A number of improvements have recently landed in lists.sr.ht. You can now search through patchsets and apply bulk updates to them, and can search them via the API as well. Another little feature, the ability to search by the sender&rsquo;s timestamp, is also going to be useful for discovering the email thread which corresponds to a git or hg commit. Post-only mailing lists (with restricted browse permissions) now also show a more useful summary page to users who may post but not read the emails.</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>debian/stable now refers to the newly-stablized Debian Buster, and Debian Bullseye has been added as debian/unstable. There is also a patch in my inbox from Simon Ser adding FreeBSD 11.3 support, which I plan on applying later this afternoon. Luca Weiss has also made some changes adding support for cloning repos into a different name than the URL&rsquo;s basename, which along with improved support for private repos has fleshed out our GitHub integration a bit more. Thanks to both!</p> <h2 id="mansrht">man.sr.ht</h2> <p>The realization of this workstream is still a ways out, but I wanted to mention that there have been patches and discussion hanging about on the sr.ht-dev list for overhauling man.sr.ht&rsquo;s repo storage mechanism. Ryan Chan has been working on moving man.sr.ht&rsquo;s git repos into your git.sr.ht account, so that you can use git.sr.ht to browse their history and files like any other git repo. We also plan to make wikis available by adding them as branches of existing repositories. This workstream is looking promising and should be completed soon, and acts as exploratory work which will influence similar overhauls for other services in the future (notably dispatch.sr.ht).</p> <h2 id="metasrht">meta.sr.ht</h2> <p>Some initial experimentation has been undergone with single-sign-on, which will address the problem of having to log into every *.sr.ht site separately. However, more problems were found than solutions, so this will take some time yet to complete. Once this is out of the way, the plan is to then add multiple email addresses per account and user groups (organizations).</p> <h2 id="interesting-projects-using-sourcehut">Interesting projects using SourceHut</h2> <p>I&rsquo;d also like to briefly mention a few cool projects which have moved to SourceHut. First, Alpine Linux has finished their migration to <a href="https://lists.alpinelinux.org">their own lists.sr.ht instance</a>. Additionally, the well known <a href="https://git.sr.ht/~kaniini/pkgconf">pkgconf</a> software is now available on SourceHut.</p> <p>Welcome to SourceHut! If you&rsquo;ve got a project of your own on SourceHut that you want to share, feel free to post about it on sr.ht-discuss. I want to know about the cool stuff you&rsquo;re building!</p> What's cooking on Sourcehut? June 2019 https://sourcehut.org/blog/2019-06-15-whats-cooking-on-sourcehut-june-2019/ Sat, 15 Jun 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-06-15-whats-cooking-on-sourcehut-june-2019/ <p>Thanks again for following SourceHut during the alpha! I hope you&rsquo;re all enjoying the service. Remember to send me your feedback, good or bad! Another month passes and another 430 users join our ranks, bringing our total to 8,990 - just shy of 9,000 strong. To our new members: welcome! And to the 874 users who&rsquo;ve chosen to pay for their account despite the alpha level of quality the service presents today, a special thanks: your support is the reason I&rsquo;m able to work so hard on the service and free software in general.</p> <h2 id="aerc">aerc</h2> <p>Direct progress on SourceHut has been somewhat slower than usual this month, because I&rsquo;ve been focusing on pushing a side project to its initial pre-release: aerc. I normally don&rsquo;t mention my other projects in these articles (though if you&rsquo;re interested, I suggest checking out my blog), but given the deep focus on email in SourceHut&rsquo;s design I find that aerc may be relevant to your interests. It&rsquo;s an email client for your terminal and it offers many design improvements over existing mail solutions. Please check it out if you have the chance!</p> <p><a href="https://aerc-mail.org">aerc-mail.org</a></p> <p>Back to your regularly scheduled updates.</p> <h2 id="mercurial-conference-update">Mercurial conference update</h2> <p>Ludovic and I attended the Mercurial conference in Paris, and met many of the Mercurial developers. I&rsquo;d like to extend my gratitude to them for putting on such a great event, and to Ludovic for coming along to make me look like less of a moron! I learned a lot about hg thanks to the patience of the Mercurial devs. We spent a lot of time talking about their plans and discussing design directions for hg.sr.ht. Our offering stands to become the premier hosting destination for the Mercurial open-source community, and I was glad we had a chance to set our course carefully towards that end.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>A big update comes today for the bug tracking service: it now has an API and webhooks! <a href="https://man.sr.ht/todo.sr.ht/api.md">The documentation is available here</a>.</p> <p>todo.sr.ht is the last major SourceHut service to receive these features, putting a bow on this workstream and unblocking a lot of others. The first of these now-unblocked workstreams is an overhaul to dispatch.sr.ht, which will bring us lots of long-awaited features. Check out <a href="https://lists.sr.ht/~sircmpwn/sr.ht-dev/%3CBUTMP0M9HDGV.16DDFWUTXGJTE%40homura%3E">the design doc</a> I posted to sr.ht-dev the other day.</p> <p>Feedback welcome!</p> <h2 id="gitsrht">git.sr.ht</h2> <p>Just minor news on this front: with git.sr.ht now growing to over 6,000 repositories, it has outgrown its old VM. To accommodate for this, I&rsquo;ve provisioned a new host in our datacenter and given half of it to git.sr.ht, giving it a lot of room for future growth. Thanks for enduring a couple hours of partial downtime this week as I migrated to the new server.</p> <p>Also, thanks to ~ignaloidas for putting git.sr.ht through a stress test with a repo designed to break web interfaces - found and fixed a few bugs thanks to that!</p> What's cooking on Sourcehut? May 2019 https://sourcehut.org/blog/2019-05-15-whats-cooking-on-sourcehut-may-2019/ Wed, 15 May 2019 00:00:00 +0000 https://sourcehut.org/blog/2019-05-15-whats-cooking-on-sourcehut-may-2019/ <p>Another month of Sourcehut development passes! I&rsquo;ve got some really cool news to share today. And a big welcome to our 240 new users, who bring our total up to 8,560. Thanks again to everyone for supporting Sourcehut during the alpha! I&rsquo;d like to briefly remind you that Sourcehut depends on your financial support to thrive - please consider <a href="https://meta.sr.ht/billing">purchasing a subscription</a> if you haven&rsquo;t yet. We just released our <a href="https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%[email protected]%3E">Q1 financial report</a>, which breaks down our income today and explains where your subscription fee ends up:</p> <p>Please let me know if you have any questions. Now to the development news!</p> <h2 id="listssrht">lists.sr.ht</h2> <p>Let&rsquo;s start with lists.sr.ht, because I have some exciting news: the initial version of web-based code review is now available! <a href="https://lists.sr.ht/~philmd/qemu/patches/5556">Check out an example here</a>.</p> <p>This is generated from a normal patch review, with no additional human input. You just respond to patch emails like you always have, and lists.sr.ht automatically applies heuristics to incoming emails to generate a web view of that discussion. In the future, I intend to expand on this with support for <em>authoring</em> reviews on the web, as well as expanding git.sr.ht to support sending patchsets from the web.</p> <h2 id="gitsrht-hgsrht">git.sr.ht, hg.sr.ht</h2> <p>git.sr.ht and hg.sr.ht both now have an API! <a href="https://man.sr.ht/git.sr.ht/api.md">The API reference can be found here</a>.</p> <p>Docs for the hg.sr.ht API are pending a design for how to expose hg.sr.ht internals over the API, but is compatible with the git.sr.ht API for any API method not dealing with git internals.</p> <p>They also support webhooks - and there&rsquo;s a pretty neat feature that comes with. When you configure a post-update webhook (equivalent to git&rsquo;s own post-update hook), you have the option of making it synchronous - this will submit the HTTP request during git push, and will print the response body to the console of the person executing git push. This can be used for custom integrations which behave like git.sr.ht does when submitting builds.sr.ht jobs, printing the URLs of the jobs which started as a consequence of your git push.</p> <p>hg.sr.ht has also grown support for the Mercurial evolve plugin this month - thanks to Ludovic again for working on that! You can enable this support on your repo&rsquo;s settings, under the &ldquo;features&rdquo; tab. Ludovic and I will be attending an Mercurial conference in Paris in 2 weeks, where we hope to discuss this and more features for hg.sr.ht in the future.</p> <h2 id="todosrht">todo.sr.ht</h2> <p>You can now submit tickets and participate in discussions on todo.sr.ht by sending an email to the tracker you want to work with. For example, to file a bug for todo.sr.ht, you can email it to ~<a href="mailto:sircmpwn/[email protected]">sircmpwn/[email protected]</a>.</p> <p>You can also do things like closing tickets via email - <a href="https://man.sr.ht/todo.sr.ht/#email-access">docs here</a>.</p> <p>I&rsquo;ve also started working on an API for todo.sr.ht. It&rsquo;s fairly complete now, but I still haven&rsquo;t written the docs. Stay tuned!</p> <h2 id="buildssrht">builds.sr.ht</h2> <p>I&rsquo;m happy to announce that OpenBSD is <a href="https://man.sr.ht/builds.sr.ht/compatibility.md#openbsd">now supported</a> on builds.sr.ht!</p> <p>Major thanks to Jarkko Oranen for putting in the work to realize this feature. Timothée Floure has also made some improvements to Fedora support, and Francesco Gazzetta added NixOS 19.03. Thanks to Andres Erbsen as well, who fixed a bug with git submodules which have been updated outside of the default branch. My friend minus has also helped me set up an experimental caching proxy for Alpine Linux packages, which shaves a few seconds off of every Alpine Linux job. I&rsquo;d like to expand this to other distros and things like npm and pypi as well.</p> <h2 id="metasrht">meta.sr.ht</h2> <p>Our friends at Gitlab were recently in the news, as several of their users had their repositories overwritten with a ransom notice. The cause of this was users with weak passwords. I&rsquo;d like to briefly share how Sourcehut is not affected by the same problem, and explain improvements I made to the service anyway.</p> <p>First, I take a backup of git.sr.ht every 5 minutes. I can restore the state of your repository as it appeared at any point in time in the event that your account is compromised. Additionally, login attempts to sr.ht are throttled and monitored for suspicious activity, and I get an alarm when someone is making a lot of login requests, which quickly leads to an IP block and an investigation of any successful logins.</p> <p>Even so, I&rsquo;ve taken this opportunity to improve Sourcehut to prevent this, by enforcing strong password requirements when you sign up and when you reset your password. No, I don&rsquo;t accomplish this with silly requirements for multiple numbers and letters and symbols and such - instead, I use Dropbox&rsquo;s zxcvbn library to estimate the entropy of your password and require a minimum inherit complexity. In the case where your password isn&rsquo;t strong enough, you&rsquo;ll be shown a message like this:</p> <p>This password is too weak - it could be cracked in less than 5 minutes if our database were broken into. Try using a few words instead of random letters and symbols. A <a href="https://passwordstore.org">password manager</a> is strongly recommended.</p> <p>I haven&rsquo;t enforced these requirements retroactively, so if you&rsquo;re concerned about your account you should <a href="https://meta.sr.ht/security">reset your password here</a>.</p> <p>You can also review your audit log on this page to check for any suspicious activity on your account. Shoot me an email if you have any concerns.</p> <h2 id="pastesrht">paste.sr.ht</h2> <p>Thanks to Mykyta Holubakha, you now have the option to set the visibility of your pastes on paste.sr.ht. The &ldquo;public&rdquo; and &ldquo;unlisted&rdquo; options are presently indistinguishable, though, because there&rsquo;s no public profile page for listing someone else&rsquo;s pastes at yet. Hopefully we&rsquo;ll see that soon!</p>