Skip to content

Add 5-repo audit bundles and private operator access - #13

Merged
erinepshovel-code merged 4 commits into
mainfrom
audit-bundles-operator
Sep 15, 2026
Merged

erinepshovel-code merged 4 commits into
mainfrom
audit-bundles-operator

Conversation

@erinepshovel-code

Copy link
Copy Markdown
Contributor

Implements the next hosted Audit surface while preserving the two-choice product rule.

  • Audit quantity is now exactly 1 repository ($5) or 5 repositories ($20).
  • Checkout Sessions are created after repository URLs are entered, so the paid session is bound to the exact repositories and tier before payment.
  • Paid return verifies live Stripe payment status, amount, tier, repository count, and URLs before running audits.
  • Adds private server-side operator access through PUBSKILL_OPERATOR_CODE; the code is never committed or stored in browser state.
  • Operator access can run the same complete 1- or 5-repository audit paths without Stripe.
  • Adds service-boundary tests for exact counts, duplicate rejection, payment metadata binding, operator code comparison, and Checkout metadata.
  • Adds HOSTED.md documenting the hosted contract and unresolved Examiner boundary.

Stripe product now has explicit active prices for $5 single audit and $20 five-repo bundle. Hosted Examiner remains hmmm pending real metering.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-15T02:21:17.904949Z bbe6dba PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@erinepshovel-code
erinepshovel-code merged commit f0cf3ab into main Sep 15, 2026
7 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbe6dba23f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread service.py
Comment on lines +99 to +102
except subprocess.TimeoutExpired:
audits.append({"repo_url": repo_url, "error": "repository audit timed out"})
except subprocess.CalledProcessError:
audits.append({"repo_url": repo_url, "error": "repository could not be cloned"})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve retry access when a paid batch item fails

When any repository in a paid bundle times out or fails to clone, run_audit_batch converts that failure into a normal result item, so /paid still returns 200; the hosted UI then labels all requested audits “complete” and removes the checkout session ID from the URL. A customer can therefore pay for five audits, receive fewer than five after a transient failure, and lose the only retry handle. Propagate a failed paid batch as non-success or persist/retry incomplete items before clearing the session.

AGENTS.md reference: AGENTS.md:L33-L33

Useful? React with 👍 / 👎.

Comment thread service.py
Comment on lines +72 to +73
if len(set(repo_urls)) != len(repo_urls):
raise ValueError("duplicate repository URLs are not allowed")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Canonicalize repository URLs before rejecting duplicates

The uniqueness check compares raw strings, so a five-repository bundle can include the same repository more than once using equivalent spellings such as https://github.com/owner/repo and https://GITHUB.COM/owner/repo. Both pass validation but clone the same target, causing a customer who intended five distinct audits to pay for duplicate output. Normalize at least the host and redundant repository-path forms before checking uniqueness.

Useful? React with 👍 / 👎.

Comment thread service.py
Comment on lines +136 to +140
success_url = os.environ.get("PUBSKILL_SUCCESS_URL", DEFAULT_SUCCESS_URL)
cancel_url = os.environ.get("PUBSKILL_CANCEL_URL", DEFAULT_CANCEL_URL)
form = [
("mode", "payment"),
("success_url", success_url),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Require the session placeholder in overridden success URLs

When PUBSKILL_SUCCESS_URL is set to an ordinary deployment URL without {CHECKOUT_SESSION_ID}, Checkout can accept payment but returns the browser without a session ID. The page only invokes loadPaid when the session_id query parameter exists, and there is no webhook or other fulfillment path, so the customer receives no audit. Validate that an override contains the placeholder or construct the session-bearing return URL from a configured base URL.

Useful? React with 👍 / 👎.

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.

1 participant