growth(day-15): npm package CLI — npx byok-relay, keywords, npm-publish workflow#53
growth(day-15): npm package CLI — npx byok-relay, keywords, npm-publish workflow#53alokit-bot wants to merge 1 commit into
Conversation
…sh workflow - bin/byok-relay.js: CLI entry with --help and --version flags; delegates to src/index.js - package.json: add bin field, files whitelist, 14 npm keywords, repo/homepage/bugs URLs; bump to 1.0.2 - README: add npm version + downloads badges; add 'Option A — zero install with npx' to Quickstart - .github/workflows/npm-publish.yml: auto-publish to npm on v* git tag via NPM_TOKEN secret npx byok-relay now works. Publish on next git tag (requires NPM_TOKEN secret in repo settings).
📝 WalkthroughWalkthroughAdds npm packaging infrastructure for Changesnpm Package Publishing
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/npm-publish.yml:
- Around line 12-15: Remove the id-token: write permission from the permissions
section in the npm-publish.yml workflow file since the job authenticates using
secrets.NPM_TOKEN rather than OIDC/provenance-based publishing. Keep only the
contents: read permission and remove the unnecessary id-token: write line to
reduce unnecessary privilege escalation.
- Around line 17-24: The GitHub Actions in the workflow use floating version
tags which create supply chain attack vulnerabilities. Replace the
`actions/checkout@v4` and `actions/setup-node@v4` floating tags with specific
immutable SHAs (using comments like `# v4.x.x` for clarity). Additionally, add
`persist-credentials: false` to the checkout step since this workflow does not
perform any authenticated git operations, preventing unnecessary exposure of
GitHub tokens to downstream steps.
In `@bin/byok-relay.js`:
- Line 62: The HTTP listener in src/index.js is only started when the module is
the main module (via require.main === module check), but bin/byok-relay.js is
requiring the module rather than running it as the main module, causing the
listener to never start. Extract the HTTP listener startup logic (the app.listen
call) from src/index.js into an exported function, then import and explicitly
call that function from bin/byok-relay.js after requiring src/index.js to ensure
the server starts when the CLI is invoked.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b8d0d603-b1c8-48fb-8602-ade4815ea8d4
📒 Files selected for processing (4)
.github/workflows/npm-publish.ymlREADME.mdbin/byok-relay.jspackage.json
| permissions: | ||
| contents: read | ||
| id-token: write | ||
|
|
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Drop id-token: write unless you publish with provenance/OIDC.
This job authenticates with secrets.NPM_TOKEN, so id-token: write is currently unnecessary extra privilege.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/npm-publish.yml around lines 12 - 15, Remove the id-token:
write permission from the permissions section in the npm-publish.yml workflow
file since the job authenticates using secrets.NPM_TOKEN rather than
OIDC/provenance-based publishing. Keep only the contents: read permission and
remove the unnecessary id-token: write line to reduce unnecessary privilege
escalation.
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
| registry-url: 'https://registry.npmjs.org' |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/npm-publish.ymlRepository: avikalpg/byok-relay
Length of output: 991
🌐 Web query:
GitHub Actions security best practices floating tags vs commit SHA pinning
💡 Result:
In the context of GitHub Actions security, the fundamental difference between floating tags and commit SHA pinning is immutability. Floating tags (e.g., @v1, @main) are mutable references. They are names that resolve to a commit only at the time of execution [1]. Because they can be moved, deleted, or recreated to point to different commits by anyone with write access to the action's repository, they do not guarantee that the code running in your pipeline remains the same over time [2][3][4]. If an action's repository or a maintainer's account is compromised, attackers can force-push malicious code to existing tags, causing your workflows to silently execute that code without any changes to your workflow configuration [5][6][7]. Commit SHA pinning (e.g., @a1b2c3d4...) involves referencing the full-length commit hash of an action. This is the only method that provides a cryptographically guaranteed, immutable reference [8][9][4]. Once pinned to a specific SHA, the workflow will always execute the exact same code, protecting you from unauthorized upstream changes [2][3]. Industry best practices, including official guidance from GitHub, strongly recommend pinning to full-length commit SHAs as the primary defense against supply chain attacks in CI/CD [10][9][1]. Key implementation recommendations: 1. Use automation: Do not manage pins manually. Tools like Dependabot, Renovate, pinact, or custom scripts can automate the process of pinning actions to SHAs while maintaining human-readable comments [11][8][12][7]. 2. Maintain readability: Use the convention of pinning to the SHA but preserving the original tag in a comment (e.g., uses: actions/checkout@a1b2c3d4... # v4.2.1) to allow automated update tools to correlate pins with semantic versions [11][12][4]. 3. Enforce via policy: Use organization or repository-level "allowed actions" policies to mandate SHA pinning [10][8][2]. When enabled, this policy causes workflows to fail if they attempt to use unpinned (tag-based) actions, ensuring compliance across the entire organization [10][2]. 4. Consider the full dependency tree: Be aware that some actions pull additional dependencies at runtime (e.g., Docker images, npm packages). Even if the action itself is pinned, these secondary dependencies may still be mutable [8][12]. Tools like poutine can help identify such risks [8].
Citations:
- 1: https://samsond.github.io/posts/why-tags-fail/
- 2: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
- 3: https://www.stepsecurity.io/blog/pinning-github-actions-for-enhanced-security-a-complete-guide
- 4: https://actsense.dev/vulnerabilities/no_hash_pinning/
- 5: https://sebastion.dev/intelligence/2026-03-12-poc-supply-chain-compromise-via-mutable-git-tag-poisoning
- 6: https://nefariousplan.com/posts/tj-actions-mutable-tags-were-always-a-lie
- 7: https://dev.to/adioof/pinning-github-actions-to-a-tag-is-mass-negligence-and-we-all-just-watched-it-happen-51p0
- 8: https://mikael.barbero.tech/blog/post/2026-03-24-stop-trusting-mutable-references/
- 9: https://docs.github.com/en/actions/reference/security/secure-use
- 10: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
- 11: https://safeguard.sh/resources/blog/github-actions-pinning-sha-vs-tag
- 12: https://emmer.dev/blog/pin-your-github-actions-to-protect-against-mutability/
🌐 Web query:
GitHub Actions checkout action persist-credentials security npm publish
💡 Result:
In GitHub Actions, the persist-credentials input of the actions/checkout action controls whether the repository's authentication token (typically GITHUB_TOKEN) is configured in the local Git environment [1][2]. Security considerations: By default, persist-credentials is set to true [1][2]. Historically, this meant the token was written directly to the .git/config file, which could expose the credential to unauthorized processes or accidentally leaked via workflow artifacts if the repository was archived and uploaded [3]. While recent updates have improved security by storing these credentials in a separate file under $RUNNER_TEMP (using Git's includeIf mechanism) [1][4], it is still a security best practice to set persist-credentials: false if your workflow does not require authenticated Git operations (such as git push or git fetch from private submodules) [5][3]. Recommendations for npm publishing: When publishing npm packages from GitHub Actions, you should avoid relying on long-lived secrets like NPM_TOKEN stored in the environment [6]. Instead, use npm Trusted Publishing, which leverages OpenID Connect (OIDC) to securely authenticate with the npm registry [7][8]. 1. Configure Trusted Publishing: In your npm package settings, add a trust relationship for your specific GitHub repository and workflow [7][6]. 2. Set permissions: Include the id-token: write permission in your workflow file to allow GitHub Actions to generate the required OIDC token [7][6]. 3. Workflow configuration: Ensure your workflow uses a GitHub-hosted runner and that you do not set the registry-url input in actions/setup-node, as this can create an .npmrc file that conflicts with the OIDC authentication flow [8]. Example workflow snippet for secure publishing: jobs: publish: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - uses: actions/checkout@v6 with: persist-credentials: false - uses: actions/setup-node@v6 with: node-version: '24' - run: npm ci - run: npm publish --provenance
Citations:
- 1: https://github.com/actions/checkout
- 2: https://github.com/actions/checkout/?tab=readme-ov-file
- 3: https://yossarian.net/til/post/actions-checkout-can-leak-github-credentials/
- 4: Persist creds to a separate file actions/checkout#2286
- 5: Remove
persist-credentialsor change the default tofalseactions/checkout#485 - 6: https://datafrog.io/en/blog/npm-trusted-publishing-github-actions-without-npm-token
- 7: https://docs.npmjs.com/trusted-publishers/
- 8: https://github.com/semantic-release/semantic-release/blob/master/docs/recipes/ci-configurations/github-actions.md
Pin GitHub Actions to immutable SHAs and disable unused checkout credentials.
Using floating tags (@v4) leaves the workflow vulnerable to supply chain attacks—attackers with repository write access can force-push malicious code to existing tags. Additionally, persist-credentials defaults to true, exposing GitHub tokens to downstream steps and tools even when not needed.
Add SHAs for actions/checkout@v4 and actions/setup-node@v4 (use # v4.x.x comments for clarity), and set persist-credentials: false on checkout since this workflow performs no authenticated git operations.
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 17-18: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 18-18: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 21-21: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 21-21: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default
(cache-poisoning)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/npm-publish.yml around lines 17 - 24, The GitHub Actions
in the workflow use floating version tags which create supply chain attack
vulnerabilities. Replace the `actions/checkout@v4` and `actions/setup-node@v4`
floating tags with specific immutable SHAs (using comments like `# v4.x.x` for
clarity). Additionally, add `persist-credentials: false` to the checkout step
since this workflow does not perform any authenticated git operations,
preventing unnecessary exposure of GitHub tokens to downstream steps.
Source: Linters/SAST tools
| } | ||
|
|
||
| // Start the server | ||
| require('../src/index.js'); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
npx byok-relay does not start the HTTP listener.
src/index.js only calls app.listen(...) when it is the main module. From this CLI, you require('../src/index.js'), so that condition is false and the process won’t start serving requests.
Suggested fix
// Start the server
-require('../src/index.js');
+const app = require('../src/index.js');
+const PORT = Number(process.env.PORT || 3000);
+app.listen(PORT, '0.0.0.0', () => {
+ console.log(`byok-relay listening on port ${PORT}`);
+});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| require('../src/index.js'); | |
| // Start the server | |
| const app = require('../src/index.js'); | |
| const PORT = Number(process.env.PORT || 3000); | |
| app.listen(PORT, '0.0.0.0', () => { | |
| console.log(`byok-relay listening on port ${PORT}`); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@bin/byok-relay.js` at line 62, The HTTP listener in src/index.js is only
started when the module is the main module (via require.main === module check),
but bin/byok-relay.js is requiring the module rather than running it as the main
module, causing the listener to never start. Extract the HTTP listener startup
logic (the app.listen call) from src/index.js into an exported function, then
import and explicitly call that function from bin/byok-relay.js after requiring
src/index.js to ensure the server starts when the CLI is invoked.
Growth Day 15 — npm package /
npx byok-relayWhat this adds
bin/byok-relay.js— CLI entry pointnpx byok-relaynow starts the server zero-install (reads.env)npx byok-relay --helpshows env vars, quick start, docs linksnpx byok-relay --versionprints versionpackage.jsonupdatesbinfield wired to CLI;fileswhitelist (only shipsbin/,src/,README.md,LICENSE,.env.example)keywords:byok,ai-gateway,llm,openai,anthropic,cors,relay,proxy,api-key,self-hosted,no-backend,frontend,lovable,boltrepository,homepage,bugsURLs added; version bumped to 1.0.2README.md— npm version + downloads badges; "Option A — zero install with npx" in Quickstart.github/workflows/npm-publish.yml— auto-publish to npm onv*tag (requiresNPM_TOKENrepo secret)To publish: add
NPM_TOKENsecret → merge PR →git tag v1.0.2 && git push --tagsMetrics (2026-06-24): stars=51 forks=0 views=17 clones=115 (14d)
Summary by CodeRabbit
New Features
--versionand--helpoptionsDocumentation
Chores