JoyJoy Docs

Five setups

What to expect on Windows with Git for Windows, on a self-hosted forge behind an internal CA, in an organisation with an OAuth policy and SAML, on a headless Codeberg machine, and at the first contact with a host you have never reached.

Not in a joy release yet

The newest joy release is v0.20.0, and it carries no joy-forge binary, no joy forge command group and no pinned host key file. This page describes the release that brings them, so that it is written down before it lands. Until that release is out, cargo install joy-cli and the installers place joy alone, and joy forge is not a command.

These five setups are the ones support is asked about. Each one says what joy does, what you have to do, and what is honestly still open.

Windows with a default Git for Windows install

What the machine looks like: credential.helper=manager, no sh on the PATH, no ssh agent service running (Windows ships it disabled), and a machine-wide proxy in the registry.

What joy does:

  • Tokens first. On this machine "no working local ssh credential" is the normal state, so joy reaches an https remote with a token and does not spend a round trip on ssh first.
  • Your helper is run directly. joy resolves manager to git-credential-manager.exe through the Git for Windows install path in the registry, and never builds the string git credential-manager and never runs git. A helper value that is shell shaped runs under the Git for Windows usr\bin\sh.exe from that same registry entry, so a missing sh on the PATH does not matter.
  • The registry proxy applies even when joy names no proxy of its own. Per-user browser settings, PAC files and WPAD do not.
  • Key files are checked first. The Windows crypto backend the ssh layer is built against reads classic PEM only: it has no ed25519, no ECDSA and no DSA, and it does not read the OpenSSH key format. joy says so by name for each key it had to skip, instead of reporting "error authenticating".

What you do: joy forge login --host github.com (or --token-stdin), and use the https remote.

A self-hosted forge behind an internal CA

What the machine looks like: an internal GitHub Enterprise Server, GitLab or Gitea, possibly on an IP literal host and a non-default port, with a certificate signed by your organisation's own CA, and no forge CLI installed anywhere.

What your operator does: ship one forges.yaml with the image (see Forges). With it the host is claimed and asked with no forge CLI at all, and the sign in runs through the OAuth application your operator registered on that instance.

The CA is the part that differs per operating system:

  • Linux: install it the normal way (update-ca-certificates), or name it once with ca_bundle or ca_dir in forges.yaml, or with http.sslCAInfo / http.sslCAPath in Git configuration. All three work.
  • macOS: add the CA to the login or System keychain and mark it trusted. The forges.yaml and Git configuration keys are refused there with a sentence that says this, because the engine cannot honour them on that system.
  • Windows: your administrator installs the CA in the Windows certificate store, usually by group policy. The same refusal sentence applies to the file-based keys.

A certificate joy cannot verify surfaces as the state tls_untrusted, with the issuer of the certificate the host presented in the detail line, so an intercepting proxy is recognisable rather than a mystery.

An organisation with an OAuth policy and SAML

What the machine looks like: the organisation restricts which OAuth applications may access it, and enforces SAML single sign-on.

What joy does: it tells the two apart and names the next step for each.

  • needs_org_approval: "Your organisation must approve Joy for this repository", with "open the approval page" as the next step. An organisation owner has to approve the application; nobody on the machine can.
  • needs_sso: "Your organisation requires single sign-on for this login", with "open the sign-on page" as the next step. GitHub returns the authorisation address in the response itself, so that address is what joy offers you.

Two limits, said plainly:

  • These two states ship untested. They cannot be exercised without an organisation that has OAuth application restrictions switched on and a second one with SAML enforced. Until such an estate exists, treat the wording of these two states as unproven, and tell us what you saw.
  • Per-repository rights on GitHub are not offered. GitHub's OAuth scopes have no read-only scope for a private repository, so a sign in that may read a private repository may also write to it. On GitLab, Gitea and Forgejo a read-only member does get a read-only credential.

Single sign-on for joyint.com itself is a different question and the answer is no: there is no SAML, OIDC or SCIM in the platform, and it is not part of this work.

A headless Codeberg machine

What the machine looks like: a server or a container with a Codeberg remote, no browser, and nobody in front of it.

The Gitea family, which Codeberg runs, offers no device code flow at all. Its sign in is a browser redirect to a loopback address, which needs a browser on that machine. So on a headless box there is exactly one way in, and it is the supported one:

joy forge login --host codeberg.org --token-stdin < /run/secrets/codeberg-token

The token is read from standard input, validated against the forge before it is stored, and never appears in a command line or a process list. If the machine has no usable credential store, joy stores it in forge-tokens.json with mode 0600 and says that is where it went.

One thing this family does not offer is token revocation for an OAuth client, so joy forge logout removes the stored credential and answers that it revoked nothing, rather than pretending. Revoke the token in Codeberg's own settings when you want it gone at the forge too.

The first contact with a host you have never reached

What happens: the machine has no line for that host in any known_hosts file, so nothing on it can say whether the key the host presents is the right one.

  • At a terminal, joy shows the host, the port, the key type and the fingerprint as SHA256: followed by base64, which is the exact string the forges publish on their own pages, and asks whether to trust it. On yes it appends one line to the first UserKnownHostsFile, hashed when your configuration asks for hashing and bracketed when the port is not 22.
  • On a server or under an agent, joy never asks and never writes. The contact fails with the state needs_host_trust, and the message names the host, the port, the fingerprint, the file that needs the line and the exact line to paste there.
  • A key that changed is refused everywhere, in every mode, and joy never rewrites the line. The message names both fingerprints, the file and the line number, and says the line has to be removed by hand.

What the fingerprint means

The fingerprint is a hash of the key the host just presented. Comparing it against the one the forge publishes is the one moment where a machine in the middle of your connection can be caught. It is worth the ten seconds it takes.

joy can also ship the published keys of the large public forges as a data file beside the binary, so that a fresh container reaches them without a person. That file ships empty today: pinning trades the check above for trust in the joy release, and it would make joy refuse a legitimate key rotation at those hosts until a new file ships. That trade has not been made yet, so an unknown host is refused on a server exactly like any other.