fix: npx pre-flight, JSON parse safety, wave redirect reason#68
fix: npx pre-flight, JSON parse safety, wave redirect reason#68chitcommit merged 1 commit intomainfrom
Conversation
- rotate-db-secret.py: verify npx is on PATH before rotating password to prevent partial failure (rotated password but can't deploy) - rotate-db-secret.py: catch json.JSONDecodeError on non-JSON API responses from 1Password Connect and Neon - wave.ts: add reason=callback_failed to catch block redirect (matching google.ts pattern) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
@coderabbitai review Please evaluate:
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdded defensive checks to the database secret rotation script—validating Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
chittyfinance | b35a90b | Mar 26 2026, 02:14 AM |
There was a problem hiding this comment.
Pull request overview
Hardens the DB secret rotation script against partial failures and malformed API responses, and aligns Wave OAuth error redirects with the existing Google callback pattern.
Changes:
- Add an
npxPATH pre-flight check to abort before rotating the Neon password if deployment tooling isn’t available. - Add
JSONDecodeErrorhandling for 1Password Connect and Neon API responses to fail fast on non-JSON bodies. - Add
reason=callback_failedto Wave OAuth callback error redirects.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
scripts/rotate-db-secret.py |
Adds npx pre-flight and safer JSON parsing error handling for external API calls. |
server/routes/wave.ts |
Adds a consistent reason query parameter on callback failure redirects. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| body = r.read() | ||
| try: | ||
| return json.loads(body) | ||
| except json.JSONDecodeError: | ||
| print(f"ERROR: 1Password Connect returned non-JSON: {body[:200]}", file=sys.stderr) | ||
| sys.exit(1) |
There was a problem hiding this comment.
In the JSONDecodeError path, body is bytes and the error message prints body[:200] directly, which ends up as a b'...' repr and may include non-printable characters. For consistency with the HTTPError branch (which decodes with errors="replace") and to keep logs readable/safe, decode/sanitize the snippet (and consider including response status/content-type instead of dumping raw bytes).
| body = r.read() | ||
| try: | ||
| return json.loads(body) | ||
| except json.JSONDecodeError: | ||
| print(f"ERROR: Neon API returned non-JSON: {body[:200]}", file=sys.stderr) | ||
| sys.exit(1) |
There was a problem hiding this comment.
Same as op_get(): this JSONDecodeError branch prints a raw bytes slice in the error message. Decode/sanitize the snippet (e.g., utf-8 with errors="replace") to keep output readable and avoid logging arbitrary bytes.
| # Pre-flight: verify npx/wrangler available BEFORE rotating the password. | ||
| # If wrangler is missing, rotating would leave a new password that can't be deployed. | ||
| if not shutil.which("npx"): | ||
| print("ERROR: npx not found on PATH. Cannot deploy secrets to Cloudflare Workers.", file=sys.stderr) | ||
| print("ABORTING before password rotation to avoid partial failure.", file=sys.stderr) | ||
| sys.exit(1) | ||
|
|
There was a problem hiding this comment.
The pre-flight comment says to verify "npx/wrangler" availability, but the code only checks npx is on PATH. Either adjust the comment to match what’s actually being validated, or extend the pre-flight to also validate that npx wrangler can run (e.g., npx wrangler --version with a short timeout) before rotating the password.
| # Pre-flight: verify npx/wrangler available BEFORE rotating the password. | |
| # If wrangler is missing, rotating would leave a new password that can't be deployed. | |
| if not shutil.which("npx"): | |
| print("ERROR: npx not found on PATH. Cannot deploy secrets to Cloudflare Workers.", file=sys.stderr) | |
| print("ABORTING before password rotation to avoid partial failure.", file=sys.stderr) | |
| sys.exit(1) | |
| # Pre-flight: verify npx and wrangler are available BEFORE rotating the password. | |
| # If wrangler is missing, rotating would leave a new password that can't be deployed. | |
| if not shutil.which("npx"): | |
| print("ERROR: npx not found on PATH. Cannot deploy secrets to Cloudflare Workers.", file=sys.stderr) | |
| print("ABORTING before password rotation to avoid partial failure.", file=sys.stderr) | |
| sys.exit(1) | |
| try: | |
| # Ensure that `npx wrangler` is runnable before proceeding. | |
| subprocess.run( | |
| ["npx", "wrangler", "--version"], | |
| stdout=subprocess.DEVNULL, | |
| stderr=subprocess.DEVNULL, | |
| check=True, | |
| timeout=10, | |
| ) | |
| except (subprocess.CalledProcessError, subprocess.TimeoutExpired, FileNotFoundError): | |
| print("ERROR: 'npx wrangler' is not available or failed to run. Cannot deploy secrets to Cloudflare Workers.", file=sys.stderr) | |
| print("ABORTING before password rotation to avoid partial failure.", file=sys.stderr) | |
| sys.exit(1) |
Code Review — PR #68Overall: LGTM with two minor notes. These are solid defensive hardening fixes. The partial-failure guard for scripts/rotate-db-secret.pynpx pre-flight check ✅
JSON parse safety ✅
server/routes/wave.ts
No security concerns introduced. No breaking changes. Cloudflare deploy succeeded per CI. |
Summary
npxis on PATH before rotating the Neon password to prevent partial failure (password rotated but can't deploy to Workers = production outage)json.JSONDecodeErroron non-JSON responses from 1Password Connect and Neon API (e.g., HTML error pages with 200 status)reason=callback_failedto catch block redirect, matching google.ts patternContext
Follow-up to PR #67 (review remediation). These three findings from the silent-failure-hunter review agent arrived after PR #67 auto-merged.
Test plan
python3 scripts/rotate-db-secret.py --helpworks without env varsnpxnot on PATH🤖 Generated with Claude Code
Summary by CodeRabbit