Skip to content

Zero-config free tier via GitHub OIDC + hosted proxy#35

Open
Svilen-Stefanov wants to merge 4 commits into
mainfrom
gha-oidc-zero-config
Open

Zero-config free tier via GitHub OIDC + hosted proxy#35
Svilen-Stefanov wants to merge 4 commits into
mainfrom
gha-oidc-zero-config

Conversation

@Svilen-Stefanov

Copy link
Copy Markdown
Contributor

What

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 (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

  • 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, precedence order —
    • byokey — current behavior verbatim (talk to the provider directly).
    • license — bearer = the 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 ::add-mask::ed. 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. 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) → drop a cb-quota-exhausted sentinel, 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.
  • README: zero-config quick start (no secret, requires id-token: write), a "More usage" section, updated inputs table.
  • Tests: 8 new (quota detection by status / marker / cause-chain; main() drops the sentinel on 402, not on other errors). Full suite 156, all green.

Verification

  • Unit: 156 tests pass; action.yml is valid YAML.
  • The 200 / 402 paths against the proxy need a real id-token: write workflow 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_url defaults to the dev gha_proxy URL with a # TODO: replace with prod URL before merge marker. After licensing-aws#10 merges + prod is deployed, bake the prod Function URL here.
  • Do not advance the v1 tag until this is merged and verified.

🤖 Generated with Claude Code

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>
@codeboarding-review

codeboarding-review Bot commented Jun 15, 2026

Copy link
Copy Markdown

Architecture review · 7 components changed

graph 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;
Loading

Colors indicate component changes compared to main: 🟩 Added · 🟨 Modified · 🟥 Removed

Workflow Orchestrator : 1 file changed
  • scripts/engine_adapter.py

⚠️ 1 architecture issue found — open CodeBoarding to explore them.

Explore this PR’s architecture in your browser or VS Code.

codeboarding-action · run 27561423263

@ivanmilevtues ivanmilevtues left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few comments, mainly the one around OPEN_ROUTER_KEY. I think it should use the same key: llm_api_key

Comment thread scripts/engine_adapter.py
# "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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

print? I hope this goes in the proper stream for the github action to capture it :D

Comment thread action.yml
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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm we should shutdown/redeploy the dev lambda

Comment thread action.yml
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"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WHy OPENROUTER_API_KEY

Shouldn't it always be llm_api_key and then you need to setup the provider + model names

Comment thread action.yml
# 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 }}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove analysis json

Comment thread action.yml
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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remember to replace

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants