RubyGems repositories serve Ruby gems to Bundler and gem. Hosted repositories take gem push, rake release, gem yank and gem owner, and answer every read Bundler and gem make: the compact index Bundler and gem 3.2.3 or later resolve from, and the specs files older gem versions and gem search read. A pushed gem installs at once, from any server. Each gem name has owners, and admins can reserve names before their first push. Hosted repositories work on every license tier. Proxy repositories of RubyGems.org (Pro) give Bundler and gem the public gems through Depotex, each checked against the SHA-256 RubyGems.org lists for it. Groups give Bundler and gem one address for your gems and RubyGems.org's, where a name you use for your own gem is never taken from RubyGems.org, and take gem push too.
Bundler 2.1 and RubyGems 3.1 (Ruby 2.7) or later work: Depotex's own tests run Ruby 2.7, 3.2, 3.3 and 4.0 against a server, each publishing, installing, and installing through a proxy of RubyGems.org, and Ruby 3.2, 3.3 and 4.0 also publishing and installing through a group. One exception: RubyGems 3.1's gem install can't install a gem that has only platform builds (such as only x86_64-linux, with no pure Ruby file); Bundler on the same Ruby can, and so can RubyGems 3.2 and later.
1. Set up Bundler
Give Bundler the repository's credentials before the first bundle install: it doesn't ask again after a refusal. Use your user name and an API token, or the token alone:
bundle config set --global https://depotex.example.com/repository/my-space/gems/ "me:$DEPOTEX_TOKEN"
# or the token on its own
bundle config set --global https://depotex.example.com/repository/my-space/gems/ "$DEPOTEX_TOKEN"
Then add the repository to the Gemfile as a source block for your own gems, and keep RubyGems.org as the global source for public ones:
source "https://rubygems.org"
source "https://depotex.example.com/repository/my-space/gems/" do
gem "acme-tools"
end
- The source block makes Bundler fetch those gems, and their dependencies, from Depotex only: a gem published on RubyGems.org under one of your internal names is never picked for them.
- With a proxy of RubyGems.org, its address takes the place of https://rubygems.org.
- Keep the trailing slash in the Gemfile and in bundle config.
- The repository's Usage tab shows these snippets with your address filled in.
2. Set up gem
gem install and gem sources take credentials in the source's address. --clear-sources makes the repository the only source for that command:
gem install --clear-sources --source "https://me:$DEPOTEX_TOKEN@depotex.example.com/repository/my-space/gems/" acme-tools
# or as a permanent source
gem sources --remove https://rubygems.org/
gem sources --add "https://me:$DEPOTEX_TOKEN@depotex.example.com/repository/my-space/gems/"
gem search, gem list --remote, gem fetch and gem outdated work against the repository too.
3. Use it in CI
Bundler also reads credentials from an environment variable named after the host: BUNDLE_ and the host name in capitals, with each . written as __ and each - as ___. gem push reads the token from GEM_HOST_API_KEY. Set both from your CI system's secrets:
export BUNDLE_DEPOTEX__EXAMPLE__COM="ci:$DEPOTEX_TOKEN"
export GEM_HOST_API_KEY="$DEPOTEX_TOKEN"
bundle install
gem push --host https://depotex.example.com/repository/my-space/gems pkg/acme-tools-1.2.0.gem
4. Publish without a stored token (Enterprise)
A CI job can publish with no secret stored at all: with workload identity, it exchanges its CI system's own identity token for a short-lived Depotex access token (dpo_at_…), which gem push takes as its key like an API token. Set it up once:
- Create a service account — Under Settings → Access management → Service accounts, add one (for example release-bot) and give it the Developer role in the space, so it may publish there.
- Create a server application — Under Settings → Access management → Applications, choose the service account under Machine access (no person), and give the application the permissions publishing needs: spaces:read, spaces:push, repo:read and repo:add.
- Trust your CI — Under the application's Workload identity, add a rule for your CI system, with conditions that name your repository and branch.
# GitHub Actions
permissions:
id-token: write
steps:
- run: |
JWT=$(curl -sH "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://depotex.example.com" | jq -r .value)
export GEM_HOST_API_KEY=$(curl -s https://depotex.example.com/api/oauth/token -d grant_type=client_credentials \
-d client_id="$DEPOTEX_CLIENT_ID" \
-d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
-d client_assertion="$JWT" | jq -r .access_token)
gem build acme-tools.gemspec
gem push --host https://depotex.example.com/repository/my-space/gems acme-tools-1.2.0.gem
The service account owns the gems it pushes first, like a person would. A client secret works in place of workload identity too (curl -u "$CLIENT_ID:$CLIENT_SECRET" … -d grant_type=client_credentials), but then the secret is stored in CI.
5. Publish
gem push takes the repository's address without a trailing slash, and an API token as its key, from GEM_HOST_API_KEY or from ~/.gem/credentials under the same address:
gem build acme-tools.gemspec
GEM_HOST_API_KEY="$DEPOTEX_TOKEN" gem push --host https://depotex.example.com/repository/my-space/gems acme-tools-1.2.0.gem
# ~/.gem/credentials (chmod 0600)
---
https://depotex.example.com/repository/my-space/gems: dpt_…
Set allowed_push_host in the gemspec to the same address, and gem push without --host, and rake release from Bundler's gem tasks, publish there and nowhere else:
spec.metadata["allowed_push_host"] = "https://depotex.example.com/repository/my-space/gems"
Never end the address with / after --host, in ~/.gem/credentials or in allowed_push_host: gem adds /api/v1/gems to it, and the doubled slash makes the push fail. Never put credentials in that address either: gem prints it, and the gemspec ships inside the gem.
- Pushing needs Publish permission. The first person to push a gem name owns it.
- A wrong, expired or revoked token is refused with Depotex's own JSON error, which gem push prints as it is: {"code":401,"error":"unauthorized","message":"Invalid API token"}, or "API token has expired" or "API token has been revoked" as the message. Without a token, the answer says to send one as GEM_HOST_API_KEY.
- Don't run gem signin --host for a Depotex repository: Depotex doesn't issue RubyGems API keys. Use an API token as the key.
- A gem built for a platform (acme-tools-1.2.0-x86_64-linux.gem) is pushed as its own file of the same version. Push the pure Ruby gem and each platform build; Bundler and gem pick the file for their platform.
- Attestations sent with gem push --attestation are kept beside the gem and shown in the browser.
- Gems are checked as they arrive: a real gem with readable metadata, every checksum in its checksums.yaml.gz matching, and a valid name, version, platform and requirements. A refused gem says why.
- RubyGems 3.1 (Ruby 2.7) asks its gem sources for the newest rubygems-update before every push and stops when none answers. With RubyGems.org reachable this needs nothing; on a network without internet access, push rubygems-update to a repository gem uses as a source, or update RubyGems (gem update --system). RubyGems 3.4 and later don't ask.
6. Yank, owners and reserved names
- Yank takes one platform's file out of the indexes: gem yank acme-tools -v 1.2.0 yanks the pure Ruby file, --platform x86_64-linux that build. Bundler and gem stop picking it, lockfiles that name it no longer install, and only repository admins can still download it. On a version's page in the browser, each platform's file has its own Yank, which asks before it acts.
- Restore brings a yanked file back (repository admins, from the version's page).
- gem yank prints the answer and exits 0 even when the yank was refused, so read its output in scripts.
- Owners: gem owner acme-tools lists them, each by email address for repository admins, otherwise by Depotex user name or, for people without one, by user id; --add and --remove take any of these for a person of your organization, so an owner can be removed with what the list printed. The version's page shows the owners too, with Add owner and remove for those allowed. A gem keeps at least one owner.
- Yanking and changing owners need Overwrite permission, or being an owner with Publish permission; repository admins always can. With Only a gem's owners push, yank and manage it on, only owners and admins can.
- Reserved names: a repository admin can reserve a gem name for its owners before its first version, in the repository's settings. Only they and admins can push it.
7. Repository settings
A hosted RubyGems repository's Settings tab has a RubyGems section (repository admins):
| Setting | What it does |
|---|---|
| Only a gem's owners push, yank and manage it | Off by default: anyone with Publish permission pushes new versions, and anyone with Overwrite permission yanks and changes owners. On: only a gem's owners (and admins) push it, yank it and change its owners. |
| Only repository admins push new gem names | New names need an admin, or a reservation. New versions of existing gems are pushed as usual. |
| Reserved gem names | Names only their owners (and admins) can push, before their first version. Each reservation has its owners. Once pushed, a name leaves the list and becomes a gem with those owners. |
A RubyGems group's RubyGems section has one switch, Hosted gems hide upstream gems of the same name, on by default (see Groups).
Changing these raises rubygems.settings.update; owner changes and reservations raise rubygems.gem.ownership, yanks rubygems.gem.update. Organization policies can refuse them.
8. Versions, platforms and policies
- A gem version is a version in Depotex, with each platform build as one of its files: the Versions tab, cleanup policies, quotas, quarantine and the block list act on the version, all its platform files together.
- A version can never be replaced: lockfiles pin each file's checksum. Pushing the same file again is answered "Gem was already pushed" and changes nothing; a different file of an existing version, or of a yanked one, is refused. New RubyGems repositories publish once.
- Versions RubyGems counts as the same are one version, for each platform, as on RubyGems.org: after 1.0, a push of 1.0.0 or 1.0.0.0 is refused ("RubyGems counts 1.0.0 as the same version as 1.0"), and after 1.0.a, one of 1.0.0.a, because = 1.0 in a Gemfile would match both. After such a version is deleted, only its own spelling can be pushed again, with the same file.
- When the integrity check finds a gem's stored file missing or damaged, pushing the same file again stores it again: the version installs again wherever it is listed.
- A deleted version can come back only with exactly the same file. Deleting a gem from the browser removes its attestation with it; the name stays known to Bundler.
- Gem names keep the casing they were first pushed with: Acme-Tools can't be pushed beside acme-tools.
- Versions are ordered as RubyGems orders them (1.0.a before 1.0, 1.10 after 1.9); a version with a letter is a pre-release. Cleanup's keep-the-newest, block-list ranges such as [1.0,1.2) and release/pre-release filters use that order. A block-list rule for RubyGems can also give its range as a RubyGems requirement, such as ~> 1.2 or >= 1.0, < 2, which it reads as gem and Bundler do.
- Each file's publish date is when it was pushed. The compact index gives it to Bundler (created_at), so Bundler 4's cooldown (bundle lock --cooldown 7 skips versions pushed in the last 7 days) and quarantine age rules count from the push.
- A hosted repository leaves blocked versions out of every index (the compact index, the specs files and the JSON API) and refuses their downloads. Quarantined versions are left out too when the repository hides quarantined versions; otherwise they stay listed and their downloads are refused. What a proxy leaves out is under Hidden versions.
- From Pro, each version gets an SBOM made from its gemspec's runtime dependencies, checked against OSV's RubyGems advisories. Most gems declare ranges such as ~> 1.2, which aren't resolved, so only dependencies pinned to one version (= 1.2.3) are checked. OSV's malicious-package records (MAL-…) show as findings with no severity once a version is stored; no policy or quarantine rule acts on them yet.
In a cluster, create RubyGems repositories only after every server runs a version of Depotex that has them, RubyGems proxy repositories only after every server runs a version that has proxies (they came after hosted ones), and RubyGems groups only after every server runs a version that has groups (they came after proxies). A server that doesn't know RubyGems, RubyGems proxies or RubyGems groups answers 404 for them.
9. Proxy repositories
A proxy repository of RubyGems.org (Pro) gives Bundler and gem every public gem through Depotex. Each gem is fetched from RubyGems.org the first time someone asks for it, checked and kept, so later installs come from Depotex, also while RubyGems.org can't be reached, and the machines that install need access to Depotex only. Create one in a space with the RubyGems.org upstream preset (https://index.rubygems.org). Another registry that serves the compact index (versions and info/), such as Artifactory, Nexus or another Depotex, works as an upstream too.
Make the proxy the Gemfile's source, with its credentials set first as for a hosted repository:
bundle config set --global https://depotex.example.com/repository/my-space/rubygems-org/ "me:$DEPOTEX_TOKEN"
# Gemfile
source "https://depotex.example.com/repository/my-space/rubygems-org/"
gem "rails"
Or keep source "https://rubygems.org" in every Gemfile and make the proxy Bundler's mirror of RubyGems.org, once per machine, CI image or job (a shell can't export the mirror's environment variable, whose name holds : and /, so run the command):
bundle config set --global mirror.https://rubygems.org https://depotex.example.com/repository/my-space/rubygems-org/
bundle config set --global https://depotex.example.com/repository/my-space/rubygems-org/ "me:$DEPOTEX_TOKEN"
gem takes the proxy as its source the same way as a hosted repository:
gem install --clear-sources --source "https://me:$DEPOTEX_TOKEN@depotex.example.com/repository/my-space/rubygems-org/" rails
# or as gem's only source
gem sources --remove https://rubygems.org/
gem sources --add "https://me:$DEPOTEX_TOKEN@depotex.example.com/repository/my-space/rubygems-org/"
The repository's Usage tab shows these with your address filled in. Keep the trailing slash. A proxy refuses gem push, gem yank and gem owner.
- What is checked: before a .gem is kept, it is compared with the SHA-256 that RubyGems.org's info file lists for that version and platform. The list of every gem (versions) is checked against the digest RubyGems.org sends with it (or, from a registry that sends none, against its length), and only ever added to: what is added must follow what the proxy already has. Each gem's info file is listed there with its MD5, which tells the proxy when its copy is out of date. names, the specs files, quick/ gemspecs and the JSON API have no checksum to compare them with, and rely on TLS.
- Checksums: new RubyGems proxies start at Use the Security setting. A gem that doesn't match is then refused while Settings → Security → Proxy checksums is on (Strict), and served with a warning in the log while it is off (Warn). This is the repository's own Checksums setting, not the integrity check's Verify checksums, which re-reads files already stored.
- The first copy: a new proxy first copies RubyGems.org's list of every gem and version (versions, about 24 MB), in a few seconds. A background job usually makes it within a minute of the repository's creation. A request for that list that comes before it's done waits up to 5 seconds, then gets 503 with Retry-After: 10: run the command again a few seconds later. Gems, gemspecs and info files are fetched from RubyGems.org meanwhile without waiting, so Bundler's fallback to the full index still installs. If the copy fails (RubyGems.org doesn't answer, or sends a list that can't be read), requests get 503 with the reason at once, and the proxy tries again after a minute, then after longer and longer waits, up to an hour, while it keeps failing. Editing the upstream makes it try again at once.
- New releases: the proxy asks RubyGems.org what changed at most once a minute, fetching only what was added, as Bundler does with its own copy. A gem released on RubyGems.org installs through the proxy within about a minute. A longer Re-check metadata after in the repository's settings makes it ask less often.
- Publish dates are the ones RubyGems.org gives each version (created_at). Quarantine age rules count from the release on RubyGems.org, not from the first install through Depotex, and Bundler 4's cooldown (bundle lock --cooldown 7) works through the proxy.
- While RubyGems.org can't be reached, the proxy serves what it has, marked stale: its copy of the list, and the info files and gems it kept (with Serve cached files while the upstream is down on, the default). A gem it never fetched can't be installed until RubyGems.org answers again.
- Each gem the proxy keeps counts toward the space's quota, and many requests for the same new gem cause one fetch, across all servers.
10. Groups
A RubyGems group is one source for Bundler and gem: your hosted gems and RubyGems.org's, through a proxy member, at one address, which takes gem push too. Groups work on every license tier (a proxy member needs Pro). Create one with your hosted repository first and the RubyGems.org proxy after it, and the hosted repository as its Default repository for uploads. As the space's default RubyGems group it also answers at https://' + HOST + '/repository/my-space/rubygems/.
Make the group the Gemfile's only source, with its credentials set first:
bundle config set --global https://depotex.example.com/repository/my-space/gems-all/ "me:$DEPOTEX_TOKEN"
# Gemfile
source "https://depotex.example.com/repository/my-space/gems-all/"
gem "acme-tools"
gem "rails"
Or keep source "https://rubygems.org" in every Gemfile and make the group Bundler's mirror of RubyGems.org, as for a proxy. gem takes it with --clear-sources, so RubyGems.org isn't asked beside it:
bundle config set --global mirror.https://rubygems.org https://depotex.example.com/repository/my-space/gems-all/
bundle config set --global https://depotex.example.com/repository/my-space/gems-all/ "me:$DEPOTEX_TOKEN"
gem install --clear-sources --source "https://me:$DEPOTEX_TOKEN@depotex.example.com/repository/my-space/gems-all/" acme-tools
Push, yank and change owners through the group with its address without the trailing slash, as for a hosted repository (--host, ~/.gem/credentials, allowed_push_host):
GEM_HOST_API_KEY="$DEPOTEX_TOKEN" gem push --host https://depotex.example.com/repository/my-space/gems-all acme-tools-1.2.0.gem
GEM_HOST_API_KEY="$DEPOTEX_TOKEN" gem yank acme-tools -v 1.2.0 --host https://depotex.example.com/repository/my-space/gems-all
The group's Usage tab shows these with your address filled in.
- Your gem names stay yours. A gem name a hosted member has, or has reserved, gets no versions from proxy members, in any casing: through the group, its info, its downloads and the JSON API come from hosted members only. Nobody can push a newer acme-tools to RubyGems.org and have Bundler pick it up through the group, and this holds for everyone, also people who can't read the hosted member. Hosted gems hide upstream gems of the same name is on by default, in the group's Settings tab; turned off, the group lists every member's versions of a name, each version and platform from the first member that has it.
- Names you don't hold yet: only hosted members' names hide upstream ones. While your internal gems are still in another registry that a proxy member reads (such as Artifactory or Nexus while you move), reserve their names in a hosted member (Reserved gem names): RubyGems.org's gems of those names are then never served through the group. Or limit the RubyGems.org proxy on the group's Members tab to everything except your names.
- Pushes go to the hosted member the group's write rules choose by the gem's name and, with Pre-releases, its version (a version with a letter, such as 1.2.0.rc1), else to the default repository for uploads. That repository's own rules apply as when you push to it: owners, reserved names, new names for admins only. The group reads the name and version from the gemspec at the start of the file, where gem build puts it; a gem built another way is refused (422): push it to the hosted repository itself. A gemspec the hosted repository would refuse (such as one with YAML aliases) is refused the same way, with the same message, and people who may publish to none of the group's hosted members are refused (403) before the gem is uploaded.
- Yanks and owner changes (gem yank, gem owner) reach the first hosted member, in order, that has the gem. Adding or removing someone who isn't in the organization, or isn't an owner, is answered "Owner could not be found.", as by the hosted repository.
- Changes reach the group: what is pushed, yanked, deleted or reserved in a hosted member shows at the next request, on any server. A new release on RubyGems.org shows within about two minutes (the proxy takes it in within a minute, the group within another). A version blocked or quarantined later leaves the group's list of gems within about a minute (RUBYGEMS_GROUP_PROXY_INTERVAL), and its download is refused at once.
- Bundler downloads only what changed: the group's list of every gem (versions) is only ever added to, so Bundler fetches its new end, a few KB, even when RubyGems.org rewrites its own list each month. When the additions reach a quarter of the list, or a month after its last fresh start once anything was added, the compaction job gives it a fresh start, which each Bundler client then downloads once in full.
- The first request of a new group, or after its members, their order, what each is asked for, what the group never serves or the switch above change, makes the group's list from its members' in the background: about 20 seconds with RubyGems.org, after the proxy's own first copy. Meanwhile the list answers 503 with Retry-After: 10: run the command again a little later. A background job usually makes it within a minute of the change, before anyone asks. People who can read only some members get a list of their own, which their first request makes.
- A proxy member that hasn't reached its upstream yet (its first copy of RubyGems.org's list failed) is left out of the group's list of gems until that copy is made, so your hosted gems still install through the group; RubyGems.org's gems join within about a minute of the copy. A proxy that has its copy serves it through the group while its upstream is down, as on its own.
- People limited to some gems (content selectors on a member's or the group's files) get those gems through the group, their info files, JSON API and downloads included, so gem install and Bundler work for them as with the member itself. Their list of gems is made for them at each request (Limits).
- Checksums: through the group, a gem's info file lists each version with the checksum of the file the group serves for it, so Bundler's checks and lockfile checksums (bundle lock --add-checksums) hold.
- A yanked file isn't served through a group, also not to repository admins (404, saying it was yanked, as its hosted repository says): download it from its hosted repository.
- Dependabot: use the group's address in the Gemfile and in a rubygems-server registry, without replaces-base, as for a repository (below).
11. Hidden versions
What Bundler and gem may install is decided before they resolve: versions they may not download are left out of what they resolve from, so they pick another version instead of failing.
- A blocked version is left out for everyone: of a hosted repository's indexes, and of what a proxy passes on (its info/ files and the JSON API). Its download is refused (403).
- With Hide quarantined versions on in the repository's settings, quarantined versions are left out too. A proxy also leaves out versions it hasn't fetched yet that a quarantine age rule would hold, judged by their publish date on RubyGems.org. With the switch off, they stay listed and their download fails with quarantined.
- Bundler and gem then resolve to the newest version that passes: with a 7-day age rule, bundle update rails picks the newest release that is at least 7 days old.
- A version hidden after Bundler cached its gem's info file stays in that cache until the gem changes on RubyGems.org (its next release or yank), because the list of gems a proxy passes on is RubyGems.org's own. bundle install then fails with the 403 instead of picking an older version. A clean Bundler cache (a new CI machine, or ~/.bundle/cache/compact_index removed) resolves without it.
- The specs files a proxy passes on (gem search, gem list --remote and gem outdated read them, and RubyGems 3.1 on Ruby 2.7 installs from them) are RubyGems.org's, so they still list hidden versions. Installing one is refused (403).
- A group leaves out what each member leaves out, and what the group's own read deny list names. A version blocked or quarantined in a hosted member after it was pushed leaves the group's list of gems within about a minute; its download is refused at once.
12. Dependabot and Renovate
- Both read api/v1/versions/<gem>.json from the repository, which Depotex answers as RubyGems.org does.
- Dependabot: keep the repository's address in the Gemfile (a hosted repository's in its source block, a group's as the source), and add a rubygems-server registry with its address and a token in dependabot.yml, without replaces-base: with it, Dependabot asks the host's root address instead of the repository's.
- Renovate: add a hostRules entry for the repository's address with a token (matchHost, token).
# .github/dependabot.yml
registries:
depotex-gems:
type: rubygems-server
url: https://depotex.example.com/repository/my-space/gems/
token: ${{ secrets.DEPOTEX_TOKEN }}
13. Moving gems from another registry
To bring gems over from GitHub Packages, GitLab, Gemfury, Nexus or Artifactory, fetch each version and push it again; each platform build is its own gem fetch --platform:
gem fetch acme-tools -v 1.1.0 --clear-sources --source "https://user:token@gems.old.example/"
GEM_HOST_API_KEY="$DEPOTEX_TOKEN" gem push --host https://depotex.example.com/repository/my-space/gems acme-tools-1.1.0.gem
The files and their checksums stay the same, so existing lockfiles keep working. Their publish dates become the dates you push them. A gem whose gemspec uses YAML aliases (&id001 and *id001, which RubyGems wrote until about 2013) is refused ("The gemspec uses a YAML alias"): such old versions can't be pushed again, but a proxy serves them as their registry has them.
A registry that serves the compact index, such as Artifactory or Nexus, can instead be the upstream of a proxy repository while you move: its gems install through Depotex as they are, with their own publish dates. In a group with your hosted repository and RubyGems.org, reserve your gem names in the hosted repository, so RubyGems.org's gems of those names are never served in their place. GitHub Packages and GitLab serve only the older dependency API, which a proxy doesn't read, so move their gems with gem fetch and gem push.
14. Networks without internet access
Gather a project's gems where there is access, for every platform it runs on, then push them:
bundle cache --all-platforms # writes vendor/cache/*.gem
for g in vendor/cache/*.gem; do
gem push --host https://depotex.example.com/repository/my-space/gems "$g"
done
A hosted repository holds only what is pushed to it: public gems pushed this way stay as they are until you push newer ones. Their publish dates are the push dates, so Bundler's cooldown and quarantine age rules count from the push, not from their release on RubyGems.org.
Where the Depotex server itself reaches RubyGems.org, a proxy repository is simpler: the machines that install need access to Depotex only, and publish dates stay RubyGems.org's.
15. In the artifact browser
Gems show by name, then their versions. A version's Overview shows what its gemspec says (summary, licenses, authors, homepage and links, the Ruby and RubyGems versions it needs, executables, native extensions, signed or attested), its owners and a Platforms table with each platform's file, size, SHA-256 and whether it is yanked, with Yank or Restore where you may. A version with some platforms yanked is marked so ("Yanked (1 of 3 platforms)"). The README tab shows the gem's README; Dependencies lists runtime and development dependencies; the Install bar shows the Gemfile lines (in the repository's source block) and gem install.
16. Server settings
| Variable | Default | What it does |
|---|---|---|
| RUBYGEMS_PUBLISH_LOCK_TTL | 2m | How long a server holds a gem name while it stores a push (10s–30m), so two pushes of one gem, on any servers, run one after the other. Raise it if pushing your largest gems takes longer |
| RUBYGEMS_LOG_CHECK_INTERVAL | 60s | How often a proxy asks its upstream what changed in its list of gems (versions) (10s–24h). A repository's Re-check metadata after, when longer, wins |
| RUBYGEMS_SYNC_WAIT | 5s | How long a request waits for a proxy's first copy of that list, or a group's first list, before it is answered 503 with Retry-After (0–1m) |
| RUBYGEMS_SYNC_TIMEOUT | 10m | The longest one copy or update of that list may take (1m–2h); making a group's first list may take twice that |
| RUBYGEMS_GROUP_PROXY_INTERVAL | 60s | How often a group takes in what its proxy members added, and versions blocked or quarantined in its hosted members since (10s–24h) |
| RUBYGEMS_GROUP_HOSTED_WAIT | 2s | How long a request for a group's list waits for another server that is adding a hosted member's change to it, before it is answered with the list as it is; the next request has the change (0–30s) |
Each server reads these at start. A value that isn't a duration in its range (such as 90 without a unit, or 1h for the publish lock) stops the server with a message naming the variable.
17. Limits
- The largest gem is 100 MiB by default, within the installation's limit, for a repository without its own size limit. A repository's own size limit (its Largest artifact setting) replaces it, larger or smaller: that's how to change it for one repository.
- People whose access to a proxy is limited to some paths (content selectors) can't read its versions, names or specs files, which list every gem (403), so Bundler can't resolve through it for them. Give people who install from a proxy read access to the whole repository.
- Through a group, people whose access is limited to some paths of the group or of a member get a list of gems made for them at each request, not one that is only added to: Bundler downloads it in full whenever something before its end changed. A group also keeps lists for at most 8 different sets of members its users can read; people of any further set get theirs made the same way. For a person limited to a few gems that takes a few milliseconds; for someone of a further set who reads a RubyGems.org proxy whole, about 1.5 seconds each time. Each server makes at most 4 of these lists at once: a request that waits 30 seconds for its turn gets 503 with Retry-After: 10, so run the command again a little later.
- A Depotex linked to this one can't proxy a RubyGems group (as for every format): link to its members instead.
- A proxy's upstream must serve the compact index (versions and info/): registries that serve only the dependency API, such as GitHub Packages and GitLab, can't be proxied.
- A proxy doesn't pass on attestations. Its api/v1/versions/<gem>.json says only what RubyGems.org's info file says (no download counts, summaries or authors). Its api/v1/gems/<gem>.json is RubyGems.org's when the newest version you may install is RubyGems.org's newest; otherwise it describes that version with what its info file says (number, platform, checksum, date and runtime dependencies) and leaves RubyGems.org's details of its own newest version (its download count, authors, summary, licenses and links) empty.
- No dependency API (api/v1/dependencies, retired by RubyGems.org too): Bundler and gem use the compact index.
- No search API (api/v1/search.json): gem search works from the specs files.
- No gem signin (Depotex doesn't issue RubyGems API keys) and no unyank through gem (RubyGems.org has none either): repository admins restore a yanked file in the browser.
- Owners have one role, owner, and aren't emailed about changes.
18. Events
| Event | When |
|---|---|
| rubygems.gem.update | A platform's file of a gem version is yanked or restored (space, repository, gem, version, platform, action) |
| rubygems.gem.ownership | An owner is added or removed, or a name is reserved or released (space, repository, gem, action, owner); refused when policies can't be read |
| rubygems.settings.update | A RubyGems repository's settings change; refused when policies can't be read |
Pushing, and a proxy keeping a gem it fetched, raise artifact.upload; deleting raises artifact.delete, as for every format. See Events.