ollama-client 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +7 -1
  4. data/docs/CLOUD.md +29 -0
  5. data/docs/CONSOLE_IMPROVEMENTS.md +256 -0
  6. data/docs/GEM_RELEASE_GUIDE.md +794 -0
  7. data/docs/GET_RUBYGEMS_SECRET.md +151 -0
  8. data/docs/QUICK_OTP_SETUP.md +80 -0
  9. data/docs/QUICK_RELEASE.md +106 -0
  10. data/docs/README.md +43 -0
  11. data/docs/RUBYGEMS_OTP_SETUP.md +199 -0
  12. data/docs/SCHEMA_FIXES.md +147 -0
  13. data/docs/TEST_UPDATES.md +107 -0
  14. data/examples/README.md +92 -0
  15. data/examples/advanced_complex_schemas.rb +6 -3
  16. data/examples/advanced_multi_step_agent.rb +2 -1
  17. data/examples/chat_console.rb +12 -3
  18. data/examples/complete_workflow.rb +14 -4
  19. data/examples/dhan_console.rb +103 -8
  20. data/examples/dhanhq/agents/technical_analysis_agent.rb +6 -1
  21. data/examples/dhanhq/schemas/agent_schemas.rb +2 -2
  22. data/examples/dhanhq_agent.rb +23 -13
  23. data/examples/dhanhq_tools.rb +311 -246
  24. data/examples/multi_step_agent_with_external_data.rb +368 -0
  25. data/{test_dhanhq_tool_calling.rb → examples/test_dhanhq_tool_calling.rb} +99 -6
  26. data/lib/ollama/agent/executor.rb +30 -30
  27. data/lib/ollama/client.rb +73 -80
  28. data/lib/ollama/dto.rb +7 -7
  29. data/lib/ollama/options.rb +17 -9
  30. data/lib/ollama/response.rb +4 -6
  31. data/lib/ollama/tool/function/parameters.rb +1 -0
  32. data/lib/ollama/version.rb +1 -1
  33. metadata +24 -9
  34. /data/{FEATURES_ADDED.md → docs/FEATURES_ADDED.md} +0 -0
  35. /data/{HANDLERS_ANALYSIS.md → docs/HANDLERS_ANALYSIS.md} +0 -0
  36. /data/{PRODUCTION_FIXES.md → docs/PRODUCTION_FIXES.md} +0 -0
  37. /data/{TESTING.md → docs/TESTING.md} +0 -0
  38. /data/{test_tool_calling.rb → examples/test_tool_calling.rb} +0 -0
@@ -0,0 +1,151 @@
1
+ # How to Get Your RubyGems OTP Secret
2
+
3
+ ## The Problem
4
+
5
+ You need the **OTP secret key** from RubyGems, not the 6-digit codes from your authenticator app.
6
+
7
+ ## What It Looks Like
8
+
9
+ ```
10
+ Example: JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP
11
+
12
+ ✅ Valid format:
13
+ - All UPPERCASE letters A-Z
14
+ - Numbers 2-7 only
15
+ - Usually 16-32 characters
16
+ - No spaces, dashes, underscores, or special characters
17
+
18
+ ❌ This is NOT it:
19
+ - 123456 (that's the OTP code, not the secret)
20
+ - abc123_secret (contains invalid characters)
21
+ - YOUR_SECRET_HERE (that's a placeholder!)
22
+ ```
23
+
24
+ ## Step-by-Step: Get Your Secret
25
+
26
+ ### Method 1: Find Existing Secret (If Saved)
27
+
28
+ When you first enabled MFA on RubyGems, it showed you a QR code and a secret key. If you saved that secret key, use it!
29
+
30
+ Check these places:
31
+ - Password manager (1Password, LastPass, Bitwarden, etc.)
32
+ - Notes app
33
+ - Screenshot of the QR code setup page
34
+
35
+ ### Method 2: Regenerate MFA on RubyGems
36
+
37
+ If you can't find the original secret, regenerate it:
38
+
39
+ #### Step 1: Log in to RubyGems
40
+ Go to https://rubygems.org
41
+
42
+ #### Step 2: Go to MFA Settings
43
+ 1. Click your profile picture/name (top right)
44
+ 2. Click **Edit Profile**
45
+ 3. Click **Multi-factor Authentication** (left sidebar)
46
+
47
+ #### Step 3: Regenerate MFA
48
+ 1. Click **"Disable Multi-factor Authentication"**
49
+ 2. Confirm disabling
50
+ 3. Click **"Enable Multi-factor Authentication"** again
51
+ 4. You'll see a QR code and the **secret key** text
52
+
53
+ #### Step 4: Save the Secret
54
+ ```
55
+ IMPORTANT: Copy the secret key NOW!
56
+ Example: JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP
57
+ ```
58
+
59
+ #### Step 5: Update Your Authenticator App
60
+ 1. Remove the old RubyGems entry from your authenticator app
61
+ 2. Scan the new QR code
62
+ 3. Enter the 6-digit code to verify
63
+
64
+ ⚠️ **Warning:** After regenerating, your old authenticator codes won't work!
65
+
66
+ ## Test Your Secret
67
+
68
+ Once you have the secret, test it:
69
+
70
+ ```bash
71
+ # Replace JBSWY... with YOUR actual secret
72
+ ruby -r rotp -e "puts ROTP::TOTP.new('JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP').now"
73
+ ```
74
+
75
+ **Expected output:**
76
+ ```
77
+ 123456 ← A 6-digit number
78
+ ```
79
+
80
+ **This number should match** your authenticator app at the same time!
81
+
82
+ ## Common Mistakes
83
+
84
+ ### ❌ Using the 6-digit OTP code
85
+ ```bash
86
+ # WRONG - This is the code, not the secret
87
+ ruby -r rotp -e "puts ROTP::TOTP.new('123456').now"
88
+ # Error: Invalid Base32 Character
89
+ ```
90
+
91
+ ### ❌ Using the placeholder text
92
+ ```bash
93
+ # WRONG - This is the example placeholder
94
+ ruby -r rotp -e "puts ROTP::TOTP.new('YOUR_SECRET_HERE').now"
95
+ # Error: Invalid Base32 Character - '_'
96
+ ```
97
+
98
+ ### ✅ Using the actual secret
99
+ ```bash
100
+ # CORRECT - Your actual Base32 secret from RubyGems
101
+ ruby -r rotp -e "puts ROTP::TOTP.new('JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP').now"
102
+ # Output: 123456
103
+ ```
104
+
105
+ ## Where to Use It
106
+
107
+ Once you have your real secret:
108
+
109
+ ### 1. Test Locally
110
+ ```bash
111
+ ruby -r rotp -e "puts ROTP::TOTP.new('YOUR_ACTUAL_SECRET').now"
112
+ ```
113
+
114
+ ### 2. Add to GitHub Secrets
115
+ 1. Go to: https://github.com/YOUR_USERNAME/YOUR_REPO/settings/secrets/actions
116
+ 2. Click **New repository secret**
117
+ 3. Name: `RUBYGEMS_OTP_SECRET`
118
+ 4. Value: Your actual secret (e.g., `JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP`)
119
+ 5. Click **Add secret**
120
+
121
+ ## Still Having Issues?
122
+
123
+ ### Error: "Invalid Base32 Character"
124
+
125
+ Your secret contains invalid characters. Check:
126
+ - No underscores (`_`)
127
+ - No lowercase letters
128
+ - No numbers 0, 1, 8, 9
129
+ - No spaces or special characters
130
+
131
+ Valid characters: `A-Z` and `2-7` only
132
+
133
+ ### Error: "OTP code doesn't match"
134
+
135
+ 1. Make sure your computer's time is synchronized
136
+ 2. Try again (codes change every 30 seconds)
137
+ 3. Verify the secret is correct
138
+
139
+ ### Can't Find Secret Anywhere
140
+
141
+ You'll need to regenerate MFA (see Method 2 above).
142
+
143
+ ## Security Note
144
+
145
+ 🔒 **Keep your OTP secret secure!**
146
+ - Don't share it publicly
147
+ - Don't commit it to git
148
+ - Store it in a password manager
149
+ - Only add it to GitHub Secrets (which are encrypted)
150
+
151
+ The secret is like a password - anyone with it can generate your OTP codes!
@@ -0,0 +1,80 @@
1
+ # Quick OTP Setup for Automated Releases
2
+
3
+ ## What You Need
4
+
5
+ Your GitHub repository needs **two secrets** for automated gem releases with MFA:
6
+
7
+ 1. **RUBYGEMS_API_KEY** - Your RubyGems API key
8
+ 2. **RUBYGEMS_OTP_SECRET** - Your RubyGems OTP secret
9
+
10
+ ## Step 1: Get Your OTP Secret
11
+
12
+ 1. Log in to https://rubygems.org
13
+ 2. Go to **Edit Profile** → **Multi-factor Authentication**
14
+ 3. Copy the **secret key** (long alphanumeric string like `JBSWY3DPEHPK3PXP`)
15
+
16
+ **⚠️ Save this securely!** If you don't see it, you may need to regenerate your MFA.
17
+
18
+ ## Step 2: Add Secrets to GitHub
19
+
20
+ 1. Go to your GitHub repo: https://github.com/shubhamtaywade82/ollama-client
21
+ 2. Click **Settings** → **Secrets and variables** → **Actions**
22
+ 3. Add two secrets:
23
+
24
+ | Secret Name | Value | Where to Get It |
25
+ | --------------------- | --------------- | ------------------------------------- |
26
+ | `RUBYGEMS_API_KEY` | Your API key | https://rubygems.org/profile/api_keys |
27
+ | `RUBYGEMS_OTP_SECRET` | Your OTP secret | RubyGems MFA settings (Step 1) |
28
+
29
+ ## Step 3: Test It
30
+
31
+ ```bash
32
+ # Bump version in lib/ollama/version.rb
33
+ # Then create and push tag:
34
+ git tag v0.2.4
35
+ git push origin v0.2.4
36
+ ```
37
+
38
+ The GitHub Action will automatically:
39
+ - Generate OTP code
40
+ - Build gem
41
+ - Push to RubyGems with OTP authentication
42
+
43
+ ## Test OTP Locally (Optional)
44
+
45
+ ```bash
46
+ gem install rotp
47
+ ruby -r rotp -e "puts ROTP::TOTP.new('YOUR_SECRET_HERE').now"
48
+ ```
49
+
50
+ This should match the code in your authenticator app.
51
+
52
+ ## Troubleshooting
53
+
54
+ ### "Invalid OTP code"
55
+ - Verify `RUBYGEMS_OTP_SECRET` is correct
56
+ - Check it matches your authenticator app
57
+
58
+ ### "unauthorized"
59
+ - Verify `RUBYGEMS_API_KEY` is correct
60
+ - Create new API key with push permissions
61
+
62
+ ### Need more help?
63
+ See full guide: `docs/RUBYGEMS_OTP_SETUP.md`
64
+
65
+ ## How It Works
66
+
67
+ ```yaml
68
+ - name: Install OTP generator
69
+ run: gem install rotp
70
+
71
+ - name: Publish gem with OTP
72
+ env:
73
+ GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
74
+ RUBYGEMS_OTP_SECRET: ${{ secrets.RUBYGEMS_OTP_SECRET }}
75
+ run: |
76
+ otp_code=$(ruby -r rotp -e "puts ROTP::TOTP.new(ENV['RUBYGEMS_OTP_SECRET']).now")
77
+ gem push "ollama-client-${version}.gem" --otp "$otp_code"
78
+ ```
79
+
80
+ That's it! Your automated releases are now secured with MFA. 🔒
@@ -0,0 +1,106 @@
1
+ # Quick Release Reference
2
+
3
+ Quick reference for releasing gems via GitHub Actions. See [GEM_RELEASE_GUIDE.md](GEM_RELEASE_GUIDE.md) for full details.
4
+
5
+ ## One-Time Setup
6
+
7
+ ### 1. RubyGems API Key
8
+ 1. Visit: https://rubygems.org/profile/edit
9
+ 2. Create API key with "Push rubygems" scope
10
+ 3. Copy the key
11
+
12
+ ### 2. GitHub Secret
13
+ 1. Go to: `https://github.com/USERNAME/REPO/settings/secrets/actions`
14
+ 2. Add secret: `RUBYGEMS_API_KEY`
15
+ 3. Paste your RubyGems API key
16
+
17
+ ### 3. Workflow File
18
+ Create `.github/workflows/release.yml`:
19
+
20
+ ```yaml
21
+ name: Release
22
+ on:
23
+ push:
24
+ tags: ["v*"]
25
+ jobs:
26
+ release:
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ - uses: ruby/setup-ruby@v1
31
+ with:
32
+ ruby-version: "3.3.4"
33
+ bundler-cache: true
34
+ - name: Validate version
35
+ run: |
36
+ tag_version="${GITHUB_REF#refs/tags/v}"
37
+ gem_version=$(ruby -e "require_relative 'lib/your_gem/version'; puts YourGem::VERSION")
38
+ [ "$tag_version" = "$gem_version" ] || exit 1
39
+ - name: Build and publish
40
+ env:
41
+ GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
42
+ run: |
43
+ gem build your-gem.gemspec
44
+ gem push your-gem-*.gem
45
+ ```
46
+
47
+ ## Release Process
48
+
49
+ ### Every Release
50
+
51
+ ```bash
52
+ # 1. Update version
53
+ # Edit: lib/your_gem/version.rb
54
+ VERSION = "1.2.3"
55
+
56
+ # 2. Update changelog
57
+ # Edit: CHANGELOG.md
58
+
59
+ # 3. Commit
60
+ git add lib/your_gem/version.rb CHANGELOG.md
61
+ git commit -m "Bump version to 1.2.3"
62
+ git push
63
+
64
+ # 4. Tag and push
65
+ git tag -a v1.2.3 -m "Release v1.2.3"
66
+ git push origin v1.2.3
67
+
68
+ # 5. Monitor
69
+ # https://github.com/USERNAME/REPO/actions
70
+ ```
71
+
72
+ ## Quick Commands
73
+
74
+ ```bash
75
+ # Create release script: bin/release.sh
76
+ #!/bin/bash
77
+ VERSION=$1
78
+ git tag -a v${VERSION} -m "Release v${VERSION}"
79
+ git push origin v${VERSION}
80
+ echo "✅ Releasing v${VERSION} - check GitHub Actions"
81
+
82
+ # Use it:
83
+ chmod +x bin/release.sh
84
+ ./bin/release.sh 1.2.3
85
+ ```
86
+
87
+ ## Common Issues
88
+
89
+ **Access Denied?**
90
+ - Check `RUBYGEMS_API_KEY` secret exists
91
+ - Verify API key has "Push rubygems" scope
92
+
93
+ **Version Mismatch?**
94
+ - Update `lib/your_gem/version.rb`
95
+ - Delete tag: `git tag -d v1.2.3 && git push origin :refs/tags/v1.2.3`
96
+
97
+ **Workflow Not Running?**
98
+ - Verify `.github/workflows/release.yml` exists
99
+ - Check tag format: `v1.2.3` (with v prefix)
100
+
101
+ ## Links
102
+
103
+ - **Full Guide:** [GEM_RELEASE_GUIDE.md](GEM_RELEASE_GUIDE.md)
104
+ - **Your Actions:** https://github.com/USERNAME/REPO/actions
105
+ - **RubyGems:** https://rubygems.org/profile/edit
106
+ - **GitHub Secrets:** https://github.com/USERNAME/REPO/settings/secrets/actions
data/docs/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Internal Documentation
2
+
3
+ This directory contains internal development documentation for the ollama-client gem.
4
+
5
+ ## Quick Links
6
+
7
+ - 🚀 **[Quick Release Reference](QUICK_RELEASE.md)** - Fast release checklist
8
+ - 📘 **[Complete Release Guide](GEM_RELEASE_GUIDE.md)** - Full automation setup (794 lines)
9
+
10
+ ## Contents
11
+
12
+ ### Design Documentation
13
+ - **[HANDLERS_ANALYSIS.md](HANDLERS_ANALYSIS.md)** - Analysis of handler architecture decisions (why we didn't adopt ollama-ruby's handler pattern)
14
+ - **[FEATURES_ADDED.md](FEATURES_ADDED.md)** - Features integrated from ollama-ruby that align with our agent-first philosophy
15
+ - **[PRODUCTION_FIXES.md](PRODUCTION_FIXES.md)** - Production-ready fixes for hybrid agents (JSON parsing, retry policy, etc.)
16
+ - **[SCHEMA_FIXES.md](SCHEMA_FIXES.md)** - Schema validation fixes and best practices for numeric constraints
17
+ - **[CONSOLE_IMPROVEMENTS.md](CONSOLE_IMPROVEMENTS.md)** - Interactive console UX improvements (thinking indicators, formatted tool results)
18
+
19
+ ### Testing Documentation
20
+ - **[TESTING.md](TESTING.md)** - Testing guide and examples
21
+ - **[TEST_UPDATES.md](TEST_UPDATES.md)** - Recent test updates for DhanHQ tool calling enhancements
22
+
23
+ ### CI/Automation
24
+ - **[CLOUD.md](CLOUD.md)** - Cloud agent guide for automated testing and fixes
25
+ - **[GEM_RELEASE_GUIDE.md](GEM_RELEASE_GUIDE.md)** - Complete guide for automated gem releases via GitHub Actions and git tags
26
+
27
+ ## For Users
28
+
29
+ If you're looking for user-facing documentation, see:
30
+ - [Main README](../README.md) - Getting started, API reference, examples
31
+ - [CHANGELOG](../CHANGELOG.md) - Version history and changes
32
+ - [CONTRIBUTING](../CONTRIBUTING.md) - How to contribute
33
+ - [Examples](../examples/) - Working code examples
34
+
35
+ ## For Contributors
36
+
37
+ These internal docs help maintainers understand:
38
+ - **Why** certain design decisions were made
39
+ - **What** features have been added and why
40
+ - **How** to test and maintain the codebase
41
+ - **Where** production fixes were applied
42
+
43
+ They are not intended for end users and can be safely ignored when using the gem.
@@ -0,0 +1,199 @@
1
+ # RubyGems OTP Setup for Automated Releases
2
+
3
+ This guide explains how to configure OTP (One-Time Password) authentication for automated gem releases with MFA enabled.
4
+
5
+ ## Why This Is Needed
6
+
7
+ When `rubygems_mfa_required = "true"` is set in your gemspec, RubyGems requires MFA verification for all gem pushes, including automated CI/CD releases. This guide shows how to configure GitHub Actions to generate OTP codes automatically.
8
+
9
+ ## Prerequisites
10
+
11
+ - RubyGems account with MFA enabled
12
+ - Admin access to your GitHub repository (to add secrets)
13
+ - Authenticator app (Google Authenticator, Authy, 1Password, etc.)
14
+
15
+ ## Step 1: Get Your RubyGems OTP Secret
16
+
17
+ ### Option A: From Existing MFA Setup
18
+
19
+ If you already have MFA enabled on RubyGems:
20
+
21
+ 1. **Log in to RubyGems.org**
22
+ 2. **Go to Edit Profile** → **Multi-factor Authentication**
23
+ 3. **Click "Show QR Code"** or **"Regenerate Recovery Codes"**
24
+ 4. When you see the QR code, look for the **secret key** (usually shown below the QR code)
25
+ 5. Copy the secret key (it's a long alphanumeric string like `JBSWY3DPEHPK3PXP`)
26
+
27
+ ### Option B: Enable MFA Fresh
28
+
29
+ If you're setting up MFA for the first time:
30
+
31
+ 1. **Log in to RubyGems.org**
32
+ 2. **Go to Edit Profile** → **Multi-factor Authentication**
33
+ 3. **Click "Enable MFA"**
34
+ 4. You'll see a QR code and a **secret key** below it
35
+ 5. **Copy the secret key** before scanning the QR code
36
+ 6. Scan the QR code with your authenticator app
37
+ 7. Enter the 6-digit code to verify
38
+
39
+ **⚠️ IMPORTANT:** Save the secret key securely. You'll need it for GitHub Actions.
40
+
41
+ ### What the Secret Looks Like
42
+
43
+ ```
44
+ Example: JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP
45
+ - All uppercase letters and numbers
46
+ - Typically 32 characters long
47
+ - Base32 encoded
48
+ ```
49
+
50
+ ## Step 2: Add Secrets to GitHub
51
+
52
+ ### 2.1: Add API Key Secret
53
+
54
+ 1. Go to your GitHub repository
55
+ 2. Click **Settings** → **Secrets and variables** → **Actions**
56
+ 3. Click **New repository secret**
57
+ 4. Name: `RUBYGEMS_API_KEY`
58
+ 5. Value: Your RubyGems API key (get from https://rubygems.org/profile/api_keys)
59
+ 6. Click **Add secret**
60
+
61
+ ### 2.2: Add OTP Secret
62
+
63
+ 1. Still in **Secrets and variables** → **Actions**
64
+ 2. Click **New repository secret**
65
+ 3. Name: `RUBYGEMS_OTP_SECRET`
66
+ 4. Value: Your OTP secret key (from Step 1)
67
+ 5. Click **Add secret**
68
+
69
+ ## Step 3: Verify GitHub Secrets
70
+
71
+ Your repository should now have two secrets:
72
+
73
+ ```
74
+ ✅ RUBYGEMS_API_KEY
75
+ ✅ RUBYGEMS_OTP_SECRET
76
+ ```
77
+
78
+ ## Step 4: Test the Setup
79
+
80
+ ### Test Locally First
81
+
82
+ You can test OTP generation locally before pushing:
83
+
84
+ ```bash
85
+ # Install rotp gem
86
+ gem install rotp
87
+
88
+ # Generate an OTP code (replace with your actual secret)
89
+ ruby -r rotp -e "puts ROTP::TOTP.new('YOUR_SECRET_HERE').now"
90
+ ```
91
+
92
+ This should output a 6-digit code that matches your authenticator app.
93
+
94
+ ### Test in CI/CD
95
+
96
+ 1. Bump your gem version in `lib/ollama/version.rb`
97
+ 2. Commit and push
98
+ 3. Create and push a matching tag:
99
+
100
+ ```bash
101
+ git tag v0.2.4
102
+ git push origin v0.2.4
103
+ ```
104
+
105
+ 4. Check GitHub Actions to see the release workflow run
106
+
107
+ ## How It Works
108
+
109
+ The GitHub Actions workflow:
110
+
111
+ 1. **Installs `rotp` gem** - Ruby library for generating TOTP codes
112
+ 2. **Generates OTP code** - Uses your secret to generate a 6-digit code
113
+ 3. **Pushes gem** - Runs `gem push --otp <code>` with the generated code
114
+
115
+ ```yaml
116
+ - name: Install OTP generator
117
+ run: gem install rotp
118
+
119
+ - name: Publish gem with OTP
120
+ env:
121
+ GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
122
+ RUBYGEMS_OTP_SECRET: ${{ secrets.RUBYGEMS_OTP_SECRET }}
123
+ run: |
124
+ otp_code=$(ruby -r rotp -e "puts ROTP::TOTP.new(ENV['RUBYGEMS_OTP_SECRET']).now")
125
+ gem push "ollama-client-${gem_version}.gem" --otp "$otp_code"
126
+ ```
127
+
128
+ ## Troubleshooting
129
+
130
+ ### "Invalid OTP code" Error
131
+
132
+ **Cause:** Time synchronization issue or wrong secret
133
+
134
+ **Solutions:**
135
+ 1. Verify your secret is correct
136
+ 2. Check server time is synchronized:
137
+ ```bash
138
+ date
139
+ ```
140
+ 3. Try regenerating the secret on RubyGems
141
+
142
+ ### "OTP code expired" Error
143
+
144
+ **Cause:** Code expired before being used (they last 30 seconds)
145
+
146
+ **Solution:** The workflow generates the code immediately before use, so this shouldn't happen. If it does, there may be a network delay. The workflow will need to retry.
147
+
148
+ ### "unauthorized" Error
149
+
150
+ **Cause:** API key is invalid or doesn't have push permissions
151
+
152
+ **Solutions:**
153
+ 1. Verify `RUBYGEMS_API_KEY` is correct
154
+ 2. Create a new API key with push permissions
155
+ 3. Update the secret in GitHub
156
+
157
+ ### Missing Secrets
158
+
159
+ **Error:** `RUBYGEMS_OTP_SECRET not found`
160
+
161
+ **Solution:** Ensure both secrets are added to GitHub (Settings → Secrets and variables → Actions)
162
+
163
+ ## Security Considerations
164
+
165
+ ### ✅ Pros
166
+ - MFA protection on gem releases
167
+ - OTP secret encrypted in GitHub Secrets
168
+ - No manual intervention needed
169
+ - Audit trail in GitHub Actions
170
+
171
+ ### ⚠️ Considerations
172
+ - OTP secret stored in GitHub increases attack surface
173
+ - If GitHub is compromised, attacker has both API key and OTP secret
174
+ - Alternative: Remove `rubygems_mfa_required` and rely on account-level MFA
175
+
176
+ ### Best Practices
177
+
178
+ 1. **Rotate API keys** regularly
179
+ 2. **Use scoped API keys** (push-only if possible)
180
+ 3. **Enable GitHub branch protection** on main branch
181
+ 4. **Require PR reviews** for sensitive changes
182
+ 5. **Monitor release logs** for unauthorized pushes
183
+ 6. **Regenerate OTP secret** if you suspect compromise
184
+
185
+ ## Alternative: Account-Level MFA Only
186
+
187
+ If you want simpler automation:
188
+
189
+ 1. Remove `rubygems_mfa_required` from gemspec
190
+ 2. Keep account-level MFA enabled on RubyGems
191
+ 3. Use API key only (no OTP needed)
192
+
193
+ This is the recommended approach for most projects as it provides good security with less complexity.
194
+
195
+ ## Reference
196
+
197
+ - [RubyGems MFA Documentation](https://guides.rubygems.org/setting-up-multifactor-authentication/)
198
+ - [ROTP Gem Documentation](https://github.com/mdp/rotp)
199
+ - [GitHub Encrypted Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets)