Zero-config free tier via GitHub OIDC + hosted proxy#35
Zero-config free tier via GitHub OIDC + hosted proxy#35Svilen-Stefanov wants to merge 4 commits into
Conversation
The action required an llm_api_key secret. It can now run with NO secret on a free hosted tier: when the workflow grants `permissions: id-token: write` and no key/license is given, the action mints a GitHub Actions OIDC JWT and points the engine's OPENROUTER_BASE_URL at CodeBoarding's gha_proxy, which verifies the token, meters per repository owner against a weekly cap, and swaps in the real OpenRouter key. A user key or a CodeBoarding license remain the more-usage paths. Backward compatible — stays on @v1. A secret-based workflow behaves identically (no OIDC, no base-url override, same provider preflight). Changes: - Inputs: llm_api_key now optional (default ''); add proxy_url (the gha_proxy Function URL) and license_key. - "Prepare & verify LLM key": three credential modes in precedence order — byokey (current behavior verbatim) / license (bearer = license, base-url = proxy) / oidc (mint from ACTIONS_ID_TOKEN_REQUEST_URL/_TOKEN with &audience=codeboarding-proxy, base-url = proxy). Hosted modes pin OpenRouter + default models and skip the openrouter.ai preflight; the JWT/license is masked. Writes a `mode` output. - Engine-run steps (base/head/analyze): export OPENROUTER_BASE_URL from cb-base-url when present (hosted modes only); export CB_QUOTA_SENTINEL so the adapter can flag a 402. cb-base-url added to the key-material cleanup. - Cache key folds in the credential mode so switching free-tier <-> BYO key never reuses the other mode's cached base analysis. - engine_adapter.py: detect HTTP 402 / "Resource exhausted: token limit reached" (status attr or cause chain) and drop a cb-quota-exhausted sentinel, then re-raise so the step still fails. The failure-comment step branches on the sentinel to post a "free weekly limit reached — add a key/license" comment. - README: zero-config quick start (no secret, requires id-token: write), a "More usage" section for the key/license paths, updated inputs table. - Tests: 8 new (quota detection by status/marker/cause-chain; main() drops the sentinel on 402 and not on other errors). Full suite 156, all green. The 200/402 paths against the dev proxy need a real id-token: write workflow; exercised separately. The proxy is licensing-aws#10 (deploy prod + bake the prod proxy_url default before merging this). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Architecture review · 7 components changedgraph LR
n_Workflow_Orchestrator["Workflow Orchestrator"]
n_Structural_Diff_Engine["Structural Diff Engine"]
n_Visual_Documentation_Renderer["Visual #amp; Documentation Renderer"]
n_Engagement_Feedback_Layer["Engagement #amp; Feedback Layer"]
n_Workflow_Orchestrator -- "triggers analysis and baseline mapping" --> n_Structural_Diff_Engine
n_Workflow_Orchestrator -- "orchestrates asset generation" --> n_Visual_Documentation_Renderer
n_Workflow_Orchestrator -- "initiates feedback and CTA generation" --> n_Engagement_Feedback_Layer
n_Structural_Diff_Engine -- "provides structural change data for diagrams" --> n_Visual_Documentation_Renderer
n_Visual_Documentation_Renderer -- "queries file-level change status" --> n_Structural_Diff_Engine
n_Visual_Documentation_Renderer -- "provides rendered content for user output" --> n_Engagement_Feedback_Layer
n_Engagement_Feedback_Layer -- "dispatches reports to" --> n_Workflow_Orchestrator
classDef added fill:#1f883d,stroke:#0b5d23,color:#ffffff;
classDef modified fill:#bf8700,stroke:#7d4e00,color:#ffffff;
classDef deleted fill:#cf222e,stroke:#82071e,color:#ffffff,stroke-dasharray:5 3;
class n_Workflow_Orchestrator modified;
linkStyle 1 stroke:#0b5d23,stroke-width:2px;
linkStyle 0,2,3,4,5 stroke:#7d4e00,stroke-width:2px;
linkStyle 6 stroke:#82071e,stroke-width:2px,stroke-dasharray:5 3;
Colors indicate component changes compared to Workflow Orchestrator : 1 file changed
Explore this PR’s architecture in your browser or VS Code. codeboarding-action · run 27561423263 |
ivanmilevtues
left a comment
There was a problem hiding this comment.
Few comments, mainly the one around OPEN_ROUTER_KEY. I think it should use the same key: llm_api_key
| # "add a key/license" comment, then re-raise so the step still fails. | ||
| if _is_quota_exhausted(exc): | ||
| _flag_quota_exhausted() | ||
| print(f"::error::{_QUOTA_MARKER}", flush=True) |
There was a problem hiding this comment.
print? I hope this goes in the proper stream for the github action to capture it :D
| proxy_url: | ||
| description: 'Base URL of the CodeBoarding hosted LLM proxy used for the free tier (no llm_api_key) and for license_key mode. The engine''s OPENROUTER_BASE_URL is pointed here; the proxy verifies the GitHub OIDC token, meters per repo owner, and swaps in the real key. Override only to point at a self-hosted/dev proxy.' | ||
| required: false | ||
| default: 'https://3nx4t5rjssktkdxj7ytze2bkqi0mfysy.lambda-url.us-east-1.on.aws' # TODO: replace dev URL with the prod gha_proxy Function URL before merge |
There was a problem hiding this comment.
hmm we should shutdown/redeploy the dev lambda
| echo "::error::proxy_url is empty but no llm_api_key was provided. Set llm_api_key, or restore proxy_url." | ||
| exit 1 | ||
| fi | ||
| PROVIDER_ENV="OPENROUTER_API_KEY" |
There was a problem hiding this comment.
WHy OPENROUTER_API_KEY
Shouldn't it always be llm_api_key and then you need to setup the provider + model names
| # OpenRouter + default models regardless of inputs.llm_provider, so a repo | ||
| # that switches between free-tier and a BYO key must not reuse the other | ||
| # mode's cached base analysis. | ||
| key: cb-base-v2-${{ runner.os }}-${{ steps.guard.outputs.base_sha }}-d${{ inputs.depth_level }}-${{ inputs.engine_ref }}-${{ steps.llm.outputs.mode }}-${{ inputs.llm_provider }}-${{ inputs.agent_model }}-${{ inputs.parsing_model }} |
There was a problem hiding this comment.
i don't get what is this key for.
OpenRouter + default models regardless of inputs.llm_provider, so a repo
# that switches between free-tier and a BYO key must not reuse the other
# mode's cached base analysis.
Why not?
| "metadata": { | ||
| "generated_at": "2026-06-15T09:15:48.531752+00:00", | ||
| "commit_hash": "44b2ac573db401bf86204a07494b6bd772e983fe", | ||
| "generated_at": "2026-06-15T16:52:11.479009+00:00", |
| proxy_url: | ||
| description: 'Base URL of the CodeBoarding hosted LLM proxy used for the free tier (no llm_api_key) and for license_key mode. The engine''s OPENROUTER_BASE_URL is pointed here; the proxy verifies the GitHub OIDC token, meters per repo owner, and swaps in the real key. Override only to point at a self-hosted/dev proxy.' | ||
| required: false | ||
| default: 'https://3nx4t5rjssktkdxj7ytze2bkqi0mfysy.lambda-url.us-east-1.on.aws' # TODO: replace dev URL with the prod gha_proxy Function URL before merge |
What
The action required an
llm_api_keysecret. It can now run with no secret on a free hosted tier: when the workflow grantspermissions: id-token: writeand no key/license is given, the action mints a GitHub Actions OIDC JWT and points the engine'sOPENROUTER_BASE_URLat CodeBoarding'sgha_proxy(licensing-aws#10), which verifies the token, meters per repository owner against a weekly cap, and swaps in the real OpenRouter key.A user key or a CodeBoarding license remain the "more usage" paths. Backward compatible — stays on
@v1. A secret-based workflow behaves identically (no OIDC, no base-url override, same provider preflight).This is repo 2 of 3 for the zero-config Action (licensing-aws#10 is the proxy; the webview PR follows).
Changes
llm_api_keynow optional (default''); addproxy_url(thegha_proxyFunction URL) andlicense_key.byokey— current behavior verbatim (talk to the provider directly).license— bearer = the license, base-url = proxy.oidc— mint fromACTIONS_ID_TOKEN_REQUEST_URL/_TOKENwith&audience=codeboarding-proxy, base-url = proxy.Hosted modes pin OpenRouter + default models and skip the openrouter.ai preflight; the JWT/license is
::add-mask::ed. Writes amodeoutput.OPENROUTER_BASE_URLfromcb-base-urlwhen present (hosted modes only); exportCB_QUOTA_SENTINEL.cb-base-urladded to the key-material cleanup.engine_adapter.py: detect HTTP 402 /Resource exhausted: token limit reached(status attr or cause chain) → drop acb-quota-exhaustedsentinel, then re-raise so the step still fails. The failure-comment step branches on the sentinel → "free weekly limit reached — add a key/license" comment.id-token: write), a "More usage" section, updated inputs table.main()drops the sentinel on 402, not on other errors). Full suite 156, all green.Verification
action.ymlis valid YAML.id-token: writeworkflow run — the proxy's 401/cold-start were verified on dev in licensing-aws#10; the end-to-end 200/402 is exercised via a throwaway workflow.Before merge
proxy_urldefaults to the devgha_proxyURL with a# TODO: replace with prod URL before mergemarker. After licensing-aws#10 merges + prod is deployed, bake the prod Function URL here.v1tag until this is merged and verified.🤖 Generated with Claude Code