Skip to content

V2.0.0#3

Merged
dshevtsov merged 12 commits intomainfrom
v2.0.0
Apr 13, 2026
Merged

V2.0.0#3
dshevtsov merged 12 commits intomainfrom
v2.0.0

Conversation

@dshevtsov
Copy link
Copy Markdown

Purpose

Ship v2.0.0 of whatsup_github: security hardening, GitHub Enterprise hostname handling via environment variables, faster PR metadata loading via GraphQL, and documentation/example updates for safe configuration.

Summary

This release replaces per-PR REST lookups with a single GraphQL batch query (nodes(ids: [...])) to cut API traffic and speed up runs. YAML config loading is hardened (safe_load, path traversal checks, resolved .netrc path) and enterprise hostname moves to WHATSUP_GITHUB_ENTERPRISE_HOSTNAME with allowlist-style validation and blocking of private/internal hosts to reduce SSRF risk. Startup warns when running unauthenticated and when .netrc is world-readable.

Breaking: the membership field is removed from output and config (org membership checks are gone). Enterprise PR links in output use the enterprise:org/repo/pull/N form instead of embedding the internal hostname. The enterprise key in .whatsup.yml is no longer used for the hostname.

Other updates: Ruby 3.4.8, dependency refresh (Gemfile.lock), dotenv loading from the executable, expanded README (security, enterprise, DEBUG=1), .env.example / .netrc.example, markdownlint config, Cucumber scenario adjusted for a real public repo, and CHANGELOG entries for 2.0.0.

Migration notes

  1. Set WHATSUP_GITHUB_ENTERPRISE_HOSTNAME for GitHub Enterprise (defaults to github.com for GHEC when unset); remove hostname from committed .whatsup.yml if it was there.
  2. Drop any membership usage from config or downstream consumers of the YAML.
  3. Expect enterprise PR identifiers in output in the enterprise:... form if you parse links.

How to test

  • bundle install and run the existing test/lint workflows locally (e.g. bundle exec rake / cucumber as documented in the README).
  • Smoke the CLI against a small repo with and without credentials; with DEBUG=1, confirm query logging only when intended.

Related documentation

dshevtsov and others added 10 commits April 10, 2026 20:01
- Use YAML.safe_load with permitted_classes to prevent arbitrary object
  deserialization
- Reject config paths containing '..' or starting with '/' to block
  path traversal
- Resolve config file to absolute path with File.expand_path(path, Dir.pwd)
- Use File.basename when copying the template to prevent traversal via
  filename

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Warn at startup when running unauthenticated (rate limit: 60 req/hour)
- Add warn_if_insecure_netrc to flag world-readable ~/.netrc permissions
- Use File.expand_path('~/.netrc') instead of ENV['HOME'] for correctness
  in containerized environments
- Add require 'json' for GraphQL request serialization

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Read WHATSUP_GITHUB_ENTERPRISE_HOSTNAME from environment; default to
  github.com (GHEC) when unset, so .whatsup.yml is safe to commit to git
- Validate hostname against allowlist regex; block private/internal ranges
- Remove enterprise: key from config_reader and the host= assignment in
  pulls.rb — hostname is no longer sourced from the config file
- Override graphql_path in EnterpriseClient: relative /graphql for
  github.com (GHEC), full https://hostname/api/graphql for GHE Server

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add PULL_REQUEST_GRAPHQL query and pull_requests_by_node_ids method to
Client. EnterpriseClient inherits the method and overrides graphql_path.

In Pulls#data, replace per-PR REST pull_request calls with a single
GraphQL nodes(ids: [...]) call using node IDs from the search results.
Use snake_case field aliases in the query (merged_at, merge_commit,
is_private) so Sawyer response attributes match expected names.

Update RowCollector#collect_rows_for_a for the new GraphQL response shape
and add the pr_url helper to mask the enterprise hostname in PR links.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove the org-membership check entirely: drop @membership, @repo,
@repo_url, and @is_private from Row; remove membership: from the
yaml_formatter output hash. The feature required a separate API call
per contributor and is no longer needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Require dotenv/load in the executable so .env is loaded before any
  class constants (like access tokens) are evaluated
- Update template .whatsup.yml: use base_branch: main, replace real repo
  with placeholder my-org/my-repo, remove membership section, fix
  enterprise comment to note the env var default
- Add .env.example and .netrc.example as credential reference files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The template .whatsup.yml now uses a placeholder repo (my-org/my-repo)
which causes a 422 from the GitHub API during the Basic scenario. Add a
'Given a file named' step to create a real config using octokit/octokit.rb
and assert 'Done!' instead of the removed 'Searching on' log line.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Document WHATSUP_GITHUB_ENTERPRISE_HOSTNAME env var (replaces enterprise:
  config key); note github.com default for GHEC
- Document DEBUG=1 for opt-in query logging
- Remove membership field from 'What's generated' section
- Update enterprise link format description (enterprise:org/repo/pull/N)
- Add Local testing section with credential and DEBUG usage
- Add .markdownlint.json to relax MD013 line-length rule for tables and
  code blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace credentials.yml with .env in .gitignore; add .cursor/
- Bump .ruby-version from 3.3.0 to 3.4.8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bump version to 2.0.0 (breaking changes: membership field removed,
enterprise hostname moved to env var, enterprise link format changed).
Update repo URLs to commerce-docs organization. Update CHANGELOG.
Update all dependencies to latest compatible versions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dshevtsov dshevtsov self-assigned this Apr 11, 2026
dshevtsov and others added 2 commits April 10, 2026 20:21
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Added `faraday-retry` as a runtime dependency in the gemspec to resolve missing-gem warnings for consumers.
- Updated CHANGELOG to reflect this bug fix.
@dshevtsov dshevtsov merged commit 4622beb into main Apr 13, 2026
4 checks passed
@dshevtsov dshevtsov deleted the v2.0.0 branch April 13, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant