 Welcome to GitSign, Keyless Git commit signing. So GitSign is a project part of the six-door project. And so today we're gonna be learning about how commit signing works, how the GitSign project came to be, and then how GitSign works and how the Keyless flow just works in general. So my name's Billy Lynch, a little bit about myself. I am a software engineer over at ChainGuard. I am a maintainer for the GitSign project as well as a few other open source projects like TectonChains. I'm also a contributor to a bunch of other just random six-door projects and Tecton projects as well. I've only been at ChainGuard for a few months, so before that I was over at Google for many years. I was on the Cloud Build team, Cloud Source Positories team, and even the Google Code team. So a lot, a lot of experience and background in developer tools, Git tools, stuff like that. So if there's one thing you get out of this talk, please, please let it be. Sign your commits, whether it be with GitSign, PGP keys, SSH keys, whatever. So the reason being is, I think most of us probably know this because we're at Supply Chain SecurityCon, but supply chain attacks have been increasing more and more and more. So this is a report from Sonatype in 2021 where we saw a 650% increase for supply chain attacks. I heard that the 2022 report is gonna come out soon, and this trend is continuing. So this is a huge problem. You might have seen this diagram before, this comes from the Solso site. This sort of models a supply chain, and every single one of these red points in here is a area where the supply chain can be compromised. And there's been a lot of discussion around signing binaries, signing images, signing artifacts that we sort of pushed abroad, but signing sources equally is important, right? Because these are just inputs to your CI pipelines, these are what generate the images. So when we talk about shifting lefts, what we really wanna start doing is protecting, let me get my laser pointer, really protecting this left side of the pipeline. And the easiest way you can do that is by starting to sign your commits. So this is a real problem. So these are just some examples I've pulled recently. These are all within the last year or two. So some of them are more just like jokes, people just impersonating famous people on GitHub, sort of creating meme commits, pushing them to their repo. Some of them have been more malicious. So just last month, there was a big thread on Twitter about, oh man, have these open source repositories been compromised? They weren't actually compromised. What ended up happening was there were fake projects that looked legitimate, but they were serving fake commits. And it was hard to tell just by browsing the code whether or not these commits were legitimate or not. And it wasn't really until you dug into some of the commits and what they were doing that you could see, oh man, this is actually a problem. And so they were faking like Kubernetes, a few other projects. So these are the type of attacks that we wanna start preventing and signing is a big part of having that metadata to make these sort of policy decisions. So before we talk about HeLa signing, first I just wanna recap how Git commit signing works. So Git commit signing has been in Git for years, many, many, many years, traditionally for GPG signing. So you can tell Git to sign a commit by passing the dash uppercase S flag. This is not to be confused with the dash lowercase S flag, which is for DCO sign-offs that doesn't actually add any sort of cryptographic signature to your commits. It has a different purpose, but it's not what we're talking about here. Here we're talking about cryptographic signatures with some sort of key. And Git also has the ability to verify these commits. So it has the Git verify commit subcommands. You can also pass dash, dash show signature to Git log and it'll also show you any Git commit signatures that are in your branch. Yeah, the Git config file also has a bunch of options to make it easier to start signing your commits. So there's GPG sign commit.gpgsign, which tells Git, hey, sign every single one of my commits. You can also do this with tag. You can tell it what key to use. And more importantly, this was actually something that was added fairly recently to Git, I think within the last year or two. They added more support beyond just GPG keys. So you can sign things with X5 and 9 certificates. You can also sign things with SSH keys. So you might have seen the news in GitHub recently. The GitHub verified page now will recognize SSH keys that are associated to your accounts. I think those were added in like 2020, 2019 maybe. So still fairly recent, but GPG keys have been around forever. And what's nice is you can also specify a program to use to sign these things. And so you can sort of see where we start alluding to Git sign here. So if you're familiar with credential helpers or anything like that, basically what Git will do is if you have this program set, it'll look for it on your path. And when you try to sign something, it'll try to evoke it with some set of predetermined arguments. So it gives a really, really nice flexible sort of integration point for signing commits. So what is in a commits? So this is what a Git commit looks like on disk. If you run this Git cat file command, it'll just dump the raw commit contents. So some of the useful things here, so you can see there's this tree SHA. So Git is a Merkle tree in and of itself. So the tree SHA refers to basically the SHA of your content route, which then all your files and folders are nested within there. The parent commit, so you can have actually multiple parents. You can have any number of parents in a Git commit. This is why if you rebase a commit on top of another one, what you're doing is you're changing this parent field and that's what's causing the commit SHA to change. Even if the author and the commit message and nothing else change. Then there's two fields here, author and committer. So not everyone knows about the difference between these two. So the author is who you're attributing, authored the change. It's not necessarily authoritative, but it's just someone's email. And the committer is supposed to be the person who applied it to the repo. So in the case of a rebase, what you're doing is you may be taking someone else's commits, replaying it over your branch. So in that case, the author would remain the same, but the committer would now be you. So you're changing who actually applied it to the repo. If you use GitHub's merge queue feature, or if you're familiar with Tide for Kubernetes, those robots then become the committer field. And so you might see the commit SHA's change on submission or depending on how things get modified. And then finally we have the commit message, right? So this is just arbitrary space where you can put whatever you want to describe your commit. And if you're curious how the commit SHA is generated, all it is, it's a checksum of the compressed version of exactly this content. And yeah, so if anything in this body changes, that will cause a new commit SHA to be generated as a result. Yeah. So what's an assigned commit? So a assigned commit looks very, very similar, but now we have this new field, GPG sig. So everything in here is basically like a key value pair. And all that's included in here is just a, this is just a PEM encoded, I think base 64, possibly, I forget, but you can put the signature in here. It is called GPG sig. Even if you use X5 and 9, even if you use SSH, it's more of just a legacy thing. That's where it's been forever and they want to keep it backwards compatible. But yeah, anything in here, we can store the signature. It becomes part of the commit body. And so every time we sign the object, we're also modifying the commit SHA as well. So how signing works. So we saw before we had the commit user data, which had the parent, the author, the committer, the body. What happens is it get passed to the signing tool. So this is what is configured in your Git config. If you don't have it set, I think it defaults to open PGP, if I remember correctly. And the expectation is this comes in through standard in. The tool does whatever signing operation it needs to do. There's some arguments passed on it, depending on your Git config. And then what gets spat out to standard out is the signed message. And what Git does is it'll take the output, it'll then shove it into the commit body and then it'll recalculate the shot and that's how you get your signed commit. So this is what's happening behind the scenes when you actually run Git commit. It prompts you for the message body, it goes through this whole flow, then it puts together the whole commit and then you actually get your commit shot. Verification works the same way. So it's a little bit different, right? Because we can't just use standard in if we have two files coming in. So it basically passes in two file descriptors to the program and the expectation is the signing tool will take those. It'll say, hey, verify whether this is correct or not and then we're expecting basically a yes-no response to 01 exit code for whether this is actually a valid message or if it's incorrect. Well, so now we're gonna talk about keyless signing. And so for keyless signing, the first thing we need to talk about is, okay, why not just use traditional GPG keys and if you're already signing commits with GPG keys and you already have like good security practices and everything else, like great, continue using that, that's fantastic. But there's a lot of things you need to do in order to make sure that that process is secure. So for example, are you encrypting your GPG keys? There are password on it. How many people have just set up a passwordless SSH key? Just because it was easy and you do wanna bother with the SSH agent or anything like that. It's a very common thing. How often do you rotate your keys? Ideally, you should be doing it every couple months, if not every year. I know I definitely don't do that or I'm not good about doing that. And we're often, sometimes a little bit more lax with what we do for our own personal setup than what we would do in more productionized setup. Your keys are generally stored in a well-known location. So SSH keys.ssh, GPG, it's either .keys or something similar. If you're ever compromised, it's a very easy location to go look for any keys and if they're unencrypted, well, now you're owned. So that's a problem if you wanna protect your keys and having to make sure that no one gets access to them. How do you know whether your key is compromised and it's being used elsewhere? You may not know until it's far too late. And then finally, even if you can detect it, how do you go about revocation, notifying people, hey, this key's no longer good. Please don't trust this anymore. It's a lot to manage and that's something we want to improve. Over lunch, just today, there's actually a thread on Hacker News about SSH key signing and there's this nice quote from one of the comments that I just added in here last minute, which was, you know, random person to Hacker News, I have a pretty decent security setup but GPG is such a usability nightmare, I don't wanna touch it with a 10-foot pole and that seems to be a fairly common sentiment. Like, you can do it right, right? It is very possible to have a secure setup with GPG but for a lot of people, it's a very high barrier of entry and so we wanna make that easy, right? Ideally, we just don't wanna think about keys and when you think about what is the best password, well, the best password's the one that you don't know and that's sort of where the idea of keyless comes in, right? How can we, you know, obviously there needs to be keys, right, because we need to sign things but can we sort of generate keys on the fly, use them once, throw them away, not have to worry about them ever, right? If we sort of invalidate keys after the fact, we make them short-lived, it doesn't matter if they get sort of compromised because if they're only valid for a short period of time, we're dramatically reducing the threat of, what is the sort of blast radius that can happen if those keys are leaked? So, when we talk about keyless signatures, the main thing that we're gonna be talking about here is six-door. So I mentioned before, Git sign is part of the six-door project and the whole six-door is sort of attributed to this whole keyless signature model. So six-door is a project under the open SSF which is the open soft open-source security foundation, which is part of the Linux foundation and the whole goal of six-door is to make signing easy. So not just Git commit signing, but artifact signing, binary signing, anything, like we wanna make signing very, very easy, very accessible so that everyone, like ideally, artifact signing should be just a best practice that you do, just like unit testing, right? It should just be very, very easy, very, very simple to get started and to do. So when we talk about six-door, there's three main components that we're focused on when it comes to signing. So there's the tooling. So these could be things like Git sign. There's also another tool that a lot of people know about in six-door called Cosign, which is for container signing, which we'll go into in a little bit. There's Recor, which is a transparency log. So this is where supply chain metadata and signature metadata can be stored. It's an immutable transparency log, so it's append only. And then finally, there's Fulcio, which is a certificate authority, which allows you to take an OIDC token. So this would be, OIDC, if you're not familiar, it stands for OpenID Connect. It's basically a layer on top of OAuth that sort of standardizes some of the common attributes of how to identify users and authorize keys, authorize tokens, stuff like that. So what Fulcio does is it lets you exchange an OIDC token for a short-lived code signing cert. It's only valid for 10 minutes. And that's sort of what powers a lot of this workflow. So six-door in general has been getting a lot of adoption. There's been a few talks this week about six-door already, nice up into the right growth. There's been a lot of great proposals coming out from different package repositories, so NPM, Python, for supporting six-door. So not everyone supports it yet, but there are plans sort of set in motion to support it. See, Python has been signing their latest releases as well as Kubernetes has been signing their latest releases with six-door as well. So this is sort of a trend that we want to keep going, get more adoption, and again, just make it very, very easy to do. So six-door as a project actually runs public instances for all of these components, so Rekor or Fulcio. So you actually don't need to stand up your own infrastructure to get started. And so if you're an open-source project and you want to do artifact signing, like it's a very, very easy, low-stakes way to start doing it. So how does it work? So this is a rough overview of the flow. So we start all the way over here with the developers. So this is gonna be your tooling. So either cosine, getSign. There's also a bunch of different language libraries, Java, Python, Rust. So these are gonna initiate the flow. So what's gonna happen is the first thing you're gonna do is you're gonna go to your identity provider and you're gonna sign in, right? So this is gonna be your GitHub account, your Google account. If you're running on a Kubernetes cluster, Kubernetes clusters have built-in OIDC for projected token. So you can actually generate those and sort of authenticate as the pod workload itself. GitHub Actions also has that. I have an example of that later. So you're gonna get back this OIDC token. And so the next thing you're gonna do is you're gonna generate this key pair, right? So again, the idea is ephemeral. So again, not keyless, but sort of ephemeral keys. You're gonna send the public key to Fulcio along with this OIDC token, so over here. And you're gonna sign part of the OIDC token with your private key. So this is basically just a check to make sure that you actually do control that private key. So Fulcio is going to check that. It's gonna check, is the token valid? Is the sort of challenge that, the signing challenge that you did valid? And if it is, what it's gonna do is it's going to return you the code signing cert. It's only valid for 10 minutes. It's actually gonna be scoped within the certificate itself. It's gonna include claims that it extracted from your OIDC token. So we can actually identify you as the user later on. And then finally, the last thing it's gonna do is write the certificate to a certificate transparency log. So we can sort of look up later and monitor what certificates have been issued. And so you can actually keep track yourself. Like, hey, where's my identity being used? Things like that. Once you have the code signing cert, you can then use that to include in signatures. So in the case of container images, this would likely be, you push your container image to the registry. You push your signature to the registry as well. There's a nifty trick that cosine uses to store the signatures next to the image themselves. We won't go into it in this talk, but it is definitely interesting. Recommend looking that up later. And then finally, we're going to publish that signature that we just made to RECOR itself, right? So normally when you do X509 validation, there's this not after time that's present in the cert. And what that's supposed to mean is, hey, anything that was signed after this time, don't trust. But that's a little bit problematic for these ephemeral certs because if they're only valid for 10 minutes, we want to be able to validate things long after. And so this is where RECOR comes in, right? Because it's a append-only log because we know when the signature was added and when it was signed. What we can do later on is look up in RECOR, hey, where is this signature? Where is this key? When was it used? And we use that in place of the not after time to basically do this validation long after the fact. And what's also nice here is it's not just what key did you use, but because we have that identity information embedded in the cert, we can actually make more smarter policies, not just, again, not just the key, but like who, right? So at ChainGuard, well, we have a policy that's like, hey, make sure that things are signed by atchainguard.dev. So you can start to do smarter things like that. So I mentioned Cosign before. So Cosign was sort of one of the first client tools that was made a part of the six-door project. And so when that was first made, there was some basic functionality for signing arbitrary blocks, arbitrary data. And so there's an idea of, hey, how can we start using this in clever ways? So this is long before Git Sign Existed, long before anything like that. But so there's an idea of, hey, there's this tool called Git Notes. So Git Notes is baked into Git itself. It allows you to attach arbitrary metadata to commits. It doesn't store it in the commit itself. Basically, it stores it in a special rough space and it says, hey, for commit A, B, C, there's this note attached to it. When you look for any notes here whenever you're referencing that commit. And so there's an idea. And so there's a document called fund.md. Sadly, no longer exists. But the idea was, hey, let's use Git Notes and let's sign the commit shot and then add that as a Git note for that same commit shot, right? And so what we can do with that is we can actually go back and verify that just with the commit shot. And what's even nicer about that is what that means is when we wanna do lookups and recore, we can actually just search for the commit shot itself. So it's a very nice, easy behavior. If you wanna go and say, hey, was this commit shot signed? It's very easy to do. So it worked and it was pretty great. But there were some downsides. So before we talked about there's already this established practice and behavior for how we sign commits. And so by doing things this way, all of the other tooling that knows how to interrupt with Git signing and Git commit verification doesn't work with this because it's not looking at Git Notes. It's looking in the commit message itself for that signature. So that's not the greatest, right? While this works and while this is fairly elegant in terms of how hacks go, but it's still not ideal for a sort of general Git ecosystem sort of interrupt. So one of the things we noticed was there was this other open source project that was made by GitHub called SmimeSign. And what SmimeSign did was it used X509 certificates to sign Git commits. Now what they were targeting was sort of your more traditional X509. So this would be something you just purchased from existing certificate authority. These would be long lasting probably for a year or maybe more, but it works. And so the idea we had was hey, there's this open source project that does really cool awesome stuff and we have this other open source project that does also other cool awesome stuff with ephemeral certs. What happens if we put them together? And so we can have ephemeral certs with the X509 signing and that's how we got Git signed. So it's, I really like the story because I think it's sort of open source at its finest of like sort of melding ideas together to sort of create something new. And Git signed is exactly that, right? So it's taking the ephemeral code signing certs from six store, the X509 signing from SmimeSign and making that a nice sort of native experience within Git itself. So we're gonna do a quick demo here. So here is just a sample repo, nothing really in it. I think there's only one commit in here. So we're just going to set this up. So again, you just have to set up a few different Git configs, one time set up so you only need to do it once. So the first one just configures hey, please use Git sign for the signing. The second one says hey, use X509 for the key type. So this just configures the arguments that get sent. And then the last thing we'll do is just say, sign all commits. So all we gotta do now is make a new commits. Give it a meaningful message. And so what it's gonna do is gonna open up this URL. So this is what kicks off that OAuthflow, that OIDC flow. And so if we actually go back over here, we'll see that there's this new tab. It basically opened the URL and we're kicked to this OAuth screen. So this is running under six store.dev. This is OAuth2.6store.dev. And what we can do here is we can just click. It's gonna sign on with the OAuthflow. I'm already signed into Google, so it just worked automatically, auth successful. And if we go back here, we're done. And from here, we can verify the commit. So it is verified using the certificate. If you wanna look in the Git config, there's no tricks up my sleeve. We didn't provision any key, we didn't do anything like that. And what we can do from here is, of course, we're gonna grab the commit shot. And there's this nifty little UI that we made for querying the public recall instance. So we can just search by commit shot. So what's nice about this is we can have the same behavior as fund.md, where we just query by commit shot. And with this, we can actually go and see the raw certificate that was included within the signature. I could also run a command to parse this out, but it's very long and nasty and involves string replacement. So we're not gonna do that. So a few things to call it here. Issued by sixdoor.dev, valid only for 10 minutes. So we can theoretically use this key for another nine minutes. We're not going to. It never hit disk. As far as I'm concerned, this key is now lost. Never persisted, never to be used again. Used for code signing. Issued to billiachinger.dev. That was the account I signed in with and it was issued by accounts.google.com. And so we can use this for sort of that richer policy verification that we saw earlier. Or that I mentioned earlier. Cool, so how did this work? So I mentioned some of it already. It's basically the same process that we saw before, right? So we start with the user data. We have the basic commits. We're running it through git sign. Git sign is kicking off that OAuth flow. It does like the local host OAuth redirect. So it listens for the token to get pushed back. Exchanges the cert with fulcio. It signs the image. And then we output two things. We output the reqor entry, which is we basically sign the commit shot. And then we actually output the signature as well. So if you're paying attention, you might be asking, well, wait a minute. Before you said, well, git doesn't make the commit until the signature is generated, right? So if we don't have the commit yet, how can we actually add the commit shot to reqor? And this is actually something really clever that we're doing. If you remember, the whole commit is basically just the serialized. It's a checksum of the compressed object data. We know what the signature will be, right? Because we're signing the input data. So we know what the output should be. And if we know what the output should be, we can actually calculate the commit shot before the commit actually exists, sign it, and then output the signature for the commit to actually be made. And so it's kind of nifty because we can get somewhat transactional behavior. I mean, some extra reqor entries might be made in some odd cases, but you can guarantee that the commit won't actually be made unless that reqor entry has been successfully uploaded, which is a very, very nice behavior because you don't have to worry about, like, weird in between states. If your commit succeeds and you get that success from GitHub, or not from GitHub, from Git, you know you're good to go. Cool, so I mentioned before, use in CICD. So anything that is an OIDC issuer provider could work with Fulcio. So for the public instance, we have a set of things that we support by default, just to keep things sane, right? Because we don't want someone to come out with their own OIDC issuer and say, oh yeah, this is totally Billy, issued from some unknown URL. But we support a lot of common ones. So you saw on the human login flow, there's GitHub, Google, Microsoft. There's also support for Kubernetes clusters and there's also support for GitHub actions. So GitHub actions issues OIDC tokens for the workflows that it runs. And this is really, really cool because if you ever tried to sign anything within your GitHub actions workflows, you might notice it's kind of a pain. You either need to generate a secret, generate a key, pass it in as a secret, or you need to use the GitHub API to write the content yourself. You can't just use the Git command line because you need to go through their API in order to use their Webflow GPG key. But with this, all you need to do, we made a GitHub action that just sets up the necessary configs for you. So all you need to do is just include this line in your GitHub action config. And from there, I hit the wrong thing. Yeah, so this uses line right here. So you can just set up Git sign, it'll install Git sign, it'll set up the necessary Git configs. And any tool, any GitHub action tool that just integrates with the Git CLI directly, we'll just recognize that and sign things with Git sign with the identity of your GitHub action itself. So this is just an example of just using the Git CLI tool. The PR request, the pull request to create action that a lot of people use also works with this. Yeah, and so here's an example here, same UI of a GitHub action runner. So I ran this a few days ago, and you can see here issued by tokens.actions.githubuser.com, for a push for this commit, for this particular workflow, for this repo. And again, this gives you a lot more control because it's not just random key who has access to the key, do your developers have access to the key. The only way to generate a cert like this is to actually run on GitHub actions itself, which is pretty nifty and really cool. So I'm really excited about this for like GitOps workflows, stuff like that. And yeah, it's really, really cool. So finally, what's next? So Git sign is still under active developments. So the core sort of signing behaviors there, so you can sign commits, you can sign tags. But there's other things that we really wanna focus on. So one of the things is stricter verification policies. So not only is this a valid signature, but doing things like, hey, does the committer actually match the identity that's in the certificate? For humans, it's actually pretty easy. For machine users, not so much, right? If you remember, the GitHub action flow, there's no email in there, right? So we can't just, how do you represent that in a Git commit where it only has emails? So that's something we're still trying to work out. But it is something that we do wanna do. Source attestations. So one of the things we're starting to think about is one of the nice properties of the fund.md was it stored sort of metadata alongside commits. And that actually has some useful properties. You can imagine, hey, what if I can store an attestation that I ran like a CI job on my commit? And be able to sign that with a sort of similar Git sign flow. Being able to say, hey, I ran vulnerability scanning, hey, I ran scorecards, which is another open SSF project. If we can do that and we can have more faith in that that we can start short circuiting, hey, we don't necessarily need to rerun this for all our dependencies. We can just look for these attestations in the repos to look for the sort of additional security metadata. So that's, it's something that's also on our mind. And then finally, Git sign. If you're familiar with Cosign, you'll know that there's actually support to bring your own key. And it'll still do the whole recore flow to upload the key to make sure that that's being recorded, that's being used. We don't support that with Git sign today, but we do see that being a use case that people want to use. If you, there is a mention very, very early on, there's actually a git config option for the key ID that does get passed into the git tool for that signing tool. So we want to use that as a hook to like bring your own key and be able to use keys and KMS and things like that. So also on our mind. Yeah, and that's all I had. Yeah, thank you. Here's some contact information. And if you want to contribute, here's the link for Git sign. I would happy to have more help. So thanks. Yes, I think we have good amount of time for questions. So feel free to line up the mic there. Test, can you hear me? Yep. So, isn't part of the thing with Git is that it's like offline distributed. So if, you know, if I'm on a plane or if I don't have internet access, I can use Git and I can still sign my commits and then I can push them whatever. It feels like this is breaking that workflow. Yes. I mean, to some extent, yes, it's a trade off, right? Because we need to have that sort of transparency log and we need to be able to publish that. There's a few ways to work around that. So what some people do, like I've done this too, is like you can just disable it temporarily while you're on a plane. And then once you're done and you want to rebase and push that out for PR, you can do that later. Yeah, it's not perfect. It's a trade off, but yes, you are correct. Can't you just take the OIDC bit out? I mean, do we really need OIDC? That's, I guess that's the question because you could achieve all the same things without the OIDC check. So the OIDC bit is what's used to prove that you can generate that short-lived cert. So it's the full SEO components to generate the code-signing cert, that's the online piece, as well as the upload onto Recur. You're right that we could just sign things with it directly, but then we're sort of back where we were before with, you know, if all we're doing is just signing with keys directly, that we don't know where they're being used when they're compromised. Having that sort of longer-lived key. And not knowing, like, how do we actually go and verify that later on? Because if all we do is generate, like, a short-lived ephemeral key locally, and then we throw it away, if we don't have a Recur, then we don't have the way to look it up later to actually verify it. So there's challenges. Okay, another question. Where do things like Ubiqui kind of come into this workflow? Yeah, so that's a great question. So I know some people today are, like, signing their commits with GPG keys and their Ubiqui, and stuff like that. You could, so where I see that coming in is more around the identity protection, right? So we still want people protecting their accounts with two factor off when they sign into Google, stuff like that. So that is still very much an important bit of this whole process. But with the ephemeral keys, because you're only using them once, like, you don't necessarily get extra value of having that on the Ubiqui itself. When we're in, like, sort of a bring-your-own-key environment, that would be a use case for, like, having the key on the Ubiqui. You can still upload the use of that key to Recor. But then you would still do the full CEO bit to say, hey, this is valid for this period of time. Using this key, you'd still upload it to Recor. The only thing that changes is just you wouldn't generate the ephemeral key. You would just take it from the HSM or whatever you're using. Cool, thank you very much. Yep. Other questions? That authentication process through the browser, does that happen every time you make a commit or is it somehow preserved locally for some time? Great question. So it depends. So we do have some configuration options to make the commit flow easier. So one of the first, like, earliest pieces of feedback we got was, like, man, clicking that button every time I want to make a commit, especially if I'm doing a rebase, is really annoying. So we've actually done a few things. If I can show off one of them here. So you can specify, like, a connector ID ahead of time. So you can just say, hey, I want to sign it with Google every time. And we can do... So it's gonna go through the same flow. It's still opening the tab in the background, but it's just gonna click the button automatically and do it. So that's one way we're doing it. The other thing is we do have experimental support for credential cache. Eddie down here is actually also working on it. Which will cache the private key and the cert, so you can use it for that full 10 minute period. We are hesitant to recommend that as a default because one of the things we like very much about the ephemeral keys is the use once throw away and not have it in a place that's a known location where if your system was compromised, knows to look for it. So we are thinking about that space. Again, that's another, like, what trade-offs to make. For me personally, I just use this connector ID thing for my personal repos and it works great. The only thing is you have to go every so often and just close some tabs. But I know some people also have Chrome extensions to do automatically. Yeah, another thing, this process does this, have some kind of support for, like, making commits in a headless environment where you cannot run a browser in the same machine. Yeah, if you, if we let this go for a little bit, it'll actually time out. Oh, no, we have to unset, hold up. The short answer is yes. So this interactive flow does have a fallback for, if you wait for like 30 seconds, I think it'll prompt for a code. There's also someone who filed an issue recently. We had this working a few months ago, so I'm surprised it broke, but for device flow. So you can basically do the whole, it'll open up a tab, you input the code and it'll just sort of work that way. So yes, we do have support for sort of non-browser workflows. All right, thank you. Yep, other questions? All right, cool, we can end it early then. So thank you so much for coming. I'll stick around up here for a few minutes if you have any other questions. Thank you. Thank you. Thank you.