fix(action): accept OrcaRouter keys and recommend the free route [skip ci]

The explicit provider allowlist omitted OrcaRouter. Pass only ORCAROUTER_API_KEY to its existing Engine route and keep no-key failure closed. The setup example uses our existing public referral and orcarouter/free, with required authentication and rate/runner limits disclosed. No provider or credential fallback.

Validation:8 existing Action cases pass, expanded existing assertions cover missing Orca key, exact route, selected-secret isolation and receipt redaction. Actual unauthenticated POST orcarouter/free returned401 Invalid API key on2026-10-26; no authenticated provider completion. Whitespace pass. No workflow enabled or deployed.
This commit is contained in:
CodeWhale Bot committed 2026-10-26 00:46:11 -07:00
1 parent 81558024ca
commit 6f92f0d5e2
3 files changed
+27 -7

No files matched your search

+16 -6
View File
@@ -19,15 +19,25 @@ pins. Adding these source files does not enable a workflow.
## Setup with your own provider key
Pick `deepseek`, `anthropic`, `openrouter`, `zai`, or `modelstudio-token-plan`,
Pick `orcarouter`, `deepseek`, `anthropic`, `openrouter`, `zai`, or `modelstudio-token-plan`,
an exact model ID, and a released CLI tag. Store the matching provider key as
an Actions secret. Pass only that provider's key to the analysis job. The
Action never chooses a different credential after an authentication or payment
failure. The example uses DeepSeek; replace its provider and secret together
when choosing another route.
failure. The example uses the recommended OrcaRouter connection; replace its
provider and secret together when choosing another route.
Create or connect your own [OrcaRouter account](https://www.orcarouter.ai/ref/ref_df843907ad10d887b867),
then store its API key as `ORCAROUTER_API_KEY`. Codewhale earns a referral fee
from OrcaRouter. `orcarouter/free` is an available starting model when listed
for your workspace; it still requires an API key. A direct no-key request on
2026-10-26 returned HTTP 401. OrcaRouter's [free-route documentation](https://www.orcarouter.ai/models/orcarouter/free)
describes zero-priced usage with request-rate limits. A limit or authentication
failure does not authorize a paid fallback. GitHub runner compute has its own
cost and limits.
Set `CODEWHALE_REVIEW_VERSION` to an exact `vX.Y.Z` release and
`CODEWHALE_REVIEW_MODEL` to the chosen provider's exact model ID. Replace both
`CODEWHALE_REVIEW_MODEL` to the chosen provider's exact model ID (for example
`orcarouter/free`). Replace both
`REPLACE_WITH_REVIEWED_COMMIT_SHA` placeholders with the same reviewed Action
commit containing the publisher. Pin third-party actions to reviewed commits
under your repository's Actions policy.
@@ -64,12 +74,12 @@ jobs:
id: review
with:
version: ${{ vars.CODEWHALE_REVIEW_VERSION }}
provider: deepseek
provider: orcarouter
model: ${{ vars.CODEWHALE_REVIEW_MODEL }}
pr-number: ${{ inputs.pr-number }}
post: 'false'
env:
DEEPSEEK_API_KEY: ${{ (github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository) && secrets.DEEPSEEK_API_KEY || '' }}
ORCAROUTER_API_KEY: ${{ (github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository) && secrets.ORCAROUTER_API_KEY || '' }}
- uses: actions/upload-artifact@v7
if: steps.review.outputs.findings != ''
with:
+1 -1
View File
@@ -15,7 +15,7 @@ const REPO = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
const MODEL = /^[A-Za-z0-9][A-Za-z0-9_./:@+-]{0,199}$/;
const KEYS = {
deepseek: 'DEEPSEEK_API_KEY', anthropic: 'ANTHROPIC_API_KEY',
openrouter: 'OPENROUTER_API_KEY', zai: 'ZAI_API_KEY',
openrouter: 'OPENROUTER_API_KEY', orcarouter: 'ORCAROUTER_API_KEY', zai: 'ZAI_API_KEY',
'modelstudio-token-plan': 'MODELSTUDIO_API_KEY',
};
+10
View File
@@ -98,6 +98,7 @@ test('stale events and a head changed during fetch stop before inference', t =>
test('bad config cannot fall back to a stale vendor key or contact another GitHub host', t => {
for (const env of [
{ CODEWHALE_API_KEY: '', DEEPSEEK_API_KEY: 'stale' }, { CW_PROVIDER: 'deepseek', DEEPSEEK_API_KEY: 'stale' },
{ CODEWHALE_API_KEY: '', CW_PROVIDER: 'orcarouter', CW_MODEL: 'orcarouter/free', DEEPSEEK_API_KEY: 'stale' },
{ CW_MODEL: 'guessed-model' }, { CW_MODEL: 'provider/model\n::error::injection' },
{ CW_VERSION: 'latest' }, { CW_MAX_PASSES: '65' }, { CW_MAX_CHARS: '8388609' },
{ CW_MAX_OUTPUT_TOKENS: '1000' }, { CW_TIMEOUT_SECONDS: '0' }, { CW_POST: 'maybe' },
@@ -109,6 +110,15 @@ test('bad config cannot fall back to a stale vendor key or contact another GitHu
assert.equal(result.calls.length, 0);
}
assert.equal(settings({ ...defaults, CODEWHALE_API_KEY: '', CW_PROVIDER: 'deepseek', CW_MODEL: 'exact-model', DEEPSEEK_API_KEY: 'vendor' }).provider, 'deepseek');
const orca = fixture(t, { env: { CODEWHALE_API_KEY: '', CW_PROVIDER: 'orcarouter', CW_MODEL: 'orcarouter/free',
ORCAROUTER_API_KEY: 'orca-fixture-secret', DEEPSEEK_API_KEY: 'stale' } });
assert.equal(orca.exitCode, 0);
const review = orca.calls.find(call => call.args.includes('review'));
assert.equal(review.opts.env.ORCAROUTER_API_KEY, 'orca-fixture-secret');
assert.equal(review.opts.env.DEEPSEEK_API_KEY, undefined);
assert.equal(review.opts.env.CODEWHALE_API_KEY, undefined);
assert.equal(review.args[review.args.indexOf('--model') + 1], 'orcarouter/free');
assert.doesNotMatch(JSON.stringify(orca.saved) + orca.summary, /orca-fixture-secret/);
assert.throws(() => target({ ...defaults, GITHUB_REPOSITORY: '../x' }, event));
});