Skip to content

Include created_at in compact index /info endpoint#6380

Open
marcbest wants to merge 1 commit intorubygems:masterfrom
marcbest:feature/compact-index-created-at
Open

Include created_at in compact index /info endpoint#6380
marcbest wants to merge 1 commit intorubygems:masterfrom
marcbest:feature/compact-index-created-at

Conversation

@marcbest
Copy link
Copy Markdown

@marcbest marcbest commented Apr 1, 2026

Problem

Supply chain attacks targeting package registries are a growing concern. Other package managers have already shipped minimum age features — npm, pnpm, and yarn all allow users to reject recently published versions during resolution.

Bundler currently has no equivalent. Adding one requires knowing when each gem version was published, but the compact index has no publication timestamp. Without it, clients must make a separate V1 API call per gem (/api/v1/versions/<gem>.json) — adding seconds of latency and hitting the RubyGems.org rate limit (10 req/s) on projects with 50+ gems.

The compact index /info endpoint already carries all the version data Bundler needs during resolution — except created_at.

Solution

Pass the version's created_at (already in the SQL query) to CompactIndex::GemVersion.new as the 8th argument, formatted as ISO 8601 UTC.

Before:

name, platform, checksum, info_checksum, ruby_version, rubygems_version, = r
CompactIndex::GemVersion.new(name, platform, Version._sha256_hex(checksum),
  info_checksum, deps, ruby_version, rubygems_version)

After:

name, platform, checksum, info_checksum, ruby_version, rubygems_version, created_at, = r
CompactIndex::GemVersion.new(name, platform, Version._sha256_hex(checksum),
  info_checksum, deps, ruby_version, rubygems_version, created_at&.utc&.iso8601)

The created_at column is already selected in the requirements_and_dependencies query, included in the GROUP BY, and used for ORDER BY. It just wasn't being passed through.

Info line output

1.0.0 rack:>= 1.0|checksum:abc123,ruby:>= 2.7.0,created_at:2024-05-01T12:00:00Z

Old clients ignore unknown requirement fields, so this is fully backwards compatible.

Dependencies

Requires rubygems/compact_index#183 — adds created_at as an optional 8th field to GemVersion struct.

Pass the version's created_at timestamp to CompactIndex::GemVersion
so it is included in the /info response. The timestamp is formatted
as ISO 8601 UTC.

This enables Bundler clients to read publication dates from the
compact index directly, avoiding separate V1 API calls per gem when
implementing supply chain security features like min_age checks.

Depends on rubygems/compact_index adding created_at as an optional
8th field to the GemVersion struct.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant