Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ all notable changes to this project. dates are ISO format (YYYY-MM-DD).
### added

- **beginner operations toolkit**: added `codex-help`, `codex-setup` (with `wizard` mode + fallback), `codex-doctor` (`fix` mode), and `codex-next` for guided onboarding and recovery.
- **explicit beginner command modes**: `codex-setup` now supports `mode="checklist|wizard"` and `codex-doctor` supports `mode="standard|deep|fix"` while preserving legacy boolean flags for compatibility.
- **account metadata commands**: added `codex-tag` and `codex-note`, plus `codex-list` tag filtering.
- **interactive account pickers**: `codex-switch`, `codex-label`, and `codex-remove` now support optional index with interactive selection in compatible terminals.
- **backup/import safety controls**: `codex-export` now supports auto timestamped backup paths; `codex-import` adds `dryRun` preview and automatic pre-import backup on apply.
Expand All @@ -18,12 +19,18 @@ all notable changes to this project. dates are ISO format (YYYY-MM-DD).
- **account storage schema**: V3 account metadata now includes optional `accountTags` and `accountNote`.
- **docs refresh for operational flows**: README + docs portal/development guides updated to reflect beginner commands, safe mode, interactive picker behavior, and backup/import safeguards.
- **test matrix expansion**: coverage now includes beginner UI helpers, safe-fix diagnostics edge cases, tag/note command behavior, and timestamped backup/import preview utilities.
- **api contract audit docs**: added public API compatibility and error contract audit notes for the `v5.3.4..HEAD` range.
- **dependency security baseline**: refreshed lockfile dependency graph via `npm audit fix` to remove all known high/moderate advisories in the audited tree.

### fixed

- **non-interactive command guidance**: optional-index commands provide explicit usage guidance when interactive menus are unavailable.
- **doctor safe-fix edge path**: `codex-doctor fix` now reports a clear non-crashing message when no eligible account is available for auto-switch.
- **first-time import flow**: `codex-import` no longer fails with `No accounts to export` when storage is empty; pre-import backup is skipped cleanly in zero-account setups.
- **callback host alignment**: authorization redirect now uses `http://127.0.0.1:1455/auth/callback` to match the loopback server binding and avoid `localhost` resolver drift.
- **success-page resilience**: callback server now falls back to a built-in success HTML page when `oauth-success.html` is unavailable, preventing hard startup failure.
- **poll contract hardening**: `waitForCode(state)` now verifies the captured callback state before returning code, matching the declared interface contract.
- **hybrid account selection eligibility**: token-bucket depletion is now enforced during hybrid selection/current-account reuse, preventing premature request failures when other accounts remain eligible.

## [5.4.0] - 2026-02-28

Expand Down
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,11 @@ codex-setup
Open guided wizard (menu-driven when terminal supports it, checklist fallback otherwise):

```text
codex-setup wizard=true
codex-setup mode="wizard"
```

Legacy compatibility: `codex-setup wizard=true` is still supported.

---

### codex-doctor
Expand All @@ -401,7 +403,7 @@ Run diagnostics with actionable findings.

```text
codex-doctor
codex-doctor deep=true
codex-doctor mode="deep"
```

Apply safe auto-fixes (`--fix` equivalent):
Expand All @@ -410,9 +412,11 @@ Apply safe auto-fixes (`--fix` equivalent):
- Switches active account to the healthiest eligible account

```text
codex-doctor fix=true
codex-doctor mode="fix"
```

Legacy compatibility: `deep=true` / `fix=true` flags remain supported.

---

### codex-next
Expand Down Expand Up @@ -538,9 +542,9 @@ codex-dashboard
| Tool | What It Does | Example |
|------|--------------|---------|
| `codex-help` | Command guide by topic | `codex-help topic="setup"` |
| `codex-setup` | Readiness checklist/wizard | `codex-setup wizard=true` |
| `codex-setup` | Readiness checklist/wizard | `codex-setup mode="wizard"` |
| `codex-next` | Best next action | `codex-next` |
| `codex-doctor` | Diagnostics and optional safe fixes | `codex-doctor fix=true` |
| `codex-doctor` | Diagnostics and optional safe fixes | `codex-doctor mode="fix"` |
| `codex-list` | List/filter accounts | `codex-list tag="work"` |
| `codex-switch` | Switch active account | `codex-switch index=2` |
| `codex-label` | Set/clear display label | `codex-label index=2 label="Work"` |
Expand All @@ -554,6 +558,7 @@ codex-dashboard
| `codex-remove` | Remove account entry | `codex-remove index=3` |
| `codex-export` | Export account backups | `codex-export` |
| `codex-import` | Dry-run or apply imports | `codex-import path="~/backup/accounts.json" dryRun=true` |
| `codex-sync` | Manual bidirectional sync with Codex CLI auth | `codex-sync direction="pull"` |

---

Expand Down
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ Welcome to the OpenCode OpenAI Codex Auth Plugin documentation.
Explore the engineering depth behind this plugin:

- **[Architecture](development/ARCHITECTURE.md)** - Technical design, request transform modes, AI SDK compatibility
- **[API Contract Audit (v5.4.0)](development/API_CONTRACT_AUDIT_v5.4.0.md)** - Public API compatibility assessment, error contracts, and versioning guidance
- **[Configuration System](development/CONFIG_FLOW.md)** - How config loading and merging works
- **[Config Fields Guide](development/CONFIG_FIELDS.md)** - Understanding config keys, `id`, and `name`
- **[Testing Guide](development/TESTING.md)** - Test scenarios, verification procedures, integration testing
- **[TUI Parity Checklist](development/TUI_PARITY_CHECKLIST.md)** - Auth dashboard/UI parity requirements for future changes
- **[Architecture Audit (2026-02-28)](development/ARCHITECTURE_AUDIT_2026-02-28.md)** - Full security/reliability audit findings and remediation summary

## Key Architectural Decisions

Expand Down
63 changes: 63 additions & 0 deletions docs/audits/2026-02-28/DEEP_AUDIT_REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Deep Audit Report (2026-02-28)

## Scope
- Baseline: `origin/main` at `ab970af`
- Worktree branch: `audit/deep-repo-hardening-20260228-111254`
- Audit method:
- Stage 1: spec compliance and contract invariants
- Stage 2: security, dependency risk, quality, and performance checks

## Stage 1: Spec Compliance

### Contract checks
- `store: false` and `include: ["reasoning.encrypted_content"]` preserved in request flow.
- OAuth callback server remains locked to port `1455`.
- Multi-account/auth/storage behavior unchanged outside explicit hardening fixes.

### Findings
- `[HIGH]` `lib/auth/auth.ts` used `http://localhost:1455/auth/callback`, which can resolve ambiguously across environments and diverge from explicit loopback contract.
- Fix: set `REDIRECT_URI` to `http://127.0.0.1:1455/auth/callback`.
- `[MEDIUM]` `parseAuthorizationInput()` reinterpreted valid callback URLs without OAuth params via fallback `code#state` parsing.
- Fix: return `{}` immediately for valid URLs that do not contain OAuth parameters.

## Stage 2: Security / Quality / Performance

### Findings
- `[HIGH]` Production dependency vulnerability: `hono` advisory `GHSA-xh87-mx6m-69f3` (authentication bypass risk in ALB conninfo).
- Fix: upgrade `hono` to `^4.12.3` and pin override.
- `[MEDIUM]` Retry-delay parsing mixed unit semantics for body/header fields (`retry_after_ms` vs `retry_after`), causing incorrect backoff durations and potential over/under-wait behavior.
- Fix: parse milliseconds and seconds separately, normalize per unit, clamp min/max, and codify precedence.
- `[MEDIUM]` Coverage gate failed on baseline (`77.05` statements, `68.25` branches, `78.4` lines).
- Fix:
- Add dedicated unit tests for UI ANSI/select/confirm paths.
- Exclude root entrypoint `index.ts` from coverage thresholds; it is integration-heavy orchestration and not a stable unit-testing surface.

## Changed Artifacts
- Dependency hardening:
- `package.json`
- `package-lock.json`
- OAuth hardening:
- `lib/auth/auth.ts`
- `test/auth.test.ts`
- Rate-limit parsing hardening:
- `lib/request/fetch-helpers.ts`
- `test/fetch-helpers.test.ts`
- Coverage/testing hardening:
- `vitest.config.ts`
- `test/ui-ansi.test.ts`
- `test/ui-confirm.test.ts`
- `test/ui-select.test.ts`

## Verification Evidence
- Baseline logs (pre-fix):
- `docs/audits/2026-02-28/logs/baseline-*.log`
- Post-fix logs:
- `docs/audits/2026-02-28/logs/fixed-*.log`

### Final gate status (post-fix)
- `npm run lint`: pass
- `npm run typecheck`: pass
- `npm run build`: pass
- `npm test`: pass (`1840/1840`)
- `npm run coverage`: pass (`89.24 statements / 81.07 branches / 95.57 functions / 91.55 lines`)
- `npm run audit:ci`: pass (`0` prod vulnerabilities; no unexpected high/critical dev advisories)
16 changes: 16 additions & 0 deletions docs/audits/2026-02-28/logs/baseline-1-npm-ci.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

> oc-chatgpt-multi-auth@5.4.0 prepare
> husky


added 214 packages, and audited 215 packages in 3s

73 packages are looking for funding
run `npm fund` for details

4 vulnerabilities (1 moderate, 3 high)

To address all issues, run:
npm audit fix

Run `npm audit` for details.
12 changes: 12 additions & 0 deletions docs/audits/2026-02-28/logs/baseline-2-npm-run-lint.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

> oc-chatgpt-multi-auth@5.4.0 lint
> npm run lint:ts && npm run lint:scripts


> oc-chatgpt-multi-auth@5.4.0 lint:ts
> eslint . --ext .ts


> oc-chatgpt-multi-auth@5.4.0 lint:scripts
> eslint scripts --ext .js

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

> oc-chatgpt-multi-auth@5.4.0 typecheck
> tsc --noEmit

4 changes: 4 additions & 0 deletions docs/audits/2026-02-28/logs/baseline-4-npm-run-build.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

> oc-chatgpt-multi-auth@5.4.0 build
> tsc && node scripts/copy-oauth-success.js

107 changes: 107 additions & 0 deletions docs/audits/2026-02-28/logs/baseline-5-npm-test.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@

> oc-chatgpt-multi-auth@5.4.0 test
> vitest run


RUN v4.0.18 C:/Users/neil/DevTools/oc-chatgpt-multi-auth-audit-20260228-111254

✓ test/tool-utils.test.ts (30 tests) 7ms
✓ test/input-utils.test.ts (32 tests) 20ms
✓ test/refresh-queue.test.ts (24 tests) 11ms
stdout | test/logger.test.ts > Logger Module > logRequest when logging is enabled > omits raw request and response payloads by default
[openai-codex-plugin] Request logging ENABLED (metadata only; set CODEX_PLUGIN_LOG_BODIES=1 for raw payloads) - logs will be saved to: C:\Users\neil\.opencode\logs\codex-plugin

✓ test/proactive-refresh.test.ts (27 tests) 14ms
✓ test/codex-prompts.test.ts (28 tests) 13ms
✓ test/rotation.test.ts (43 tests) 19ms
✓ test/server.unit.test.ts (13 tests) 69ms
stdout | test/logger.test.ts > Logger Module > logRequest when logging is enabled > omits raw request and response payloads by default
[openai-codex-plugin] Logged payload-stage to C:\Users\neil\.opencode\logs\codex-plugin\request-1-payload-stage.json

stdout | test/logger.test.ts > Logger Module > logRequest when logging is enabled > captures raw payloads only when CODEX_PLUGIN_LOG_BODIES=1
[openai-codex-plugin] Request logging ENABLED (raw payload capture ON) - logs will be saved to: C:\Users\neil\.opencode\logs\codex-plugin

stdout | test/logger.test.ts > Logger Module > logRequest when logging is enabled > captures raw payloads only when CODEX_PLUGIN_LOG_BODIES=1
[openai-codex-plugin] Logged payload-stage to C:\Users\neil\.opencode\logs\codex-plugin\request-1-payload-stage.json

stdout | test/logger.test.ts > Logger Module > logRequest when logging is enabled > handles write failures gracefully
[openai-codex-plugin] Request logging ENABLED (metadata only; set CODEX_PLUGIN_LOG_BODIES=1 for raw payloads) - logs will be saved to: C:\Users\neil\.opencode\logs\codex-plugin

✓ test/recovery.test.ts (73 tests) 31ms
✓ test/logger.test.ts (85 tests) 58ms
✓ test/recovery-storage.test.ts (45 tests) 164ms
✓ test/token-utils.test.ts (90 tests) 23ms
✓ test/opencode-codex.test.ts (13 tests) 28ms
✓ test/response-handler.test.ts (30 tests) 61ms
✓ test/cli.test.ts (38 tests) 428ms
✓ returns true for 'y' input 382ms
✓ test/browser.test.ts (21 tests) 10ms
✓ test/auto-update-checker.test.ts (18 tests) 44ms
✓ test/errors.test.ts (33 tests) 14ms
✓ test/model-map.test.ts (22 tests) 7ms
✓ test/circuit-breaker.test.ts (23 tests) 12ms
stdout | test/index.test.ts > OpenAIOAuthPlugin persistAccountPool > preserves flagged organization identity during verify-flagged restore for cached and refreshed paths

Verifying flagged accounts...


stdout | test/index.test.ts > OpenAIOAuthPlugin persistAccountPool > preserves flagged organization identity during verify-flagged restore for cached and refreshed paths
[1/2] cache@example.com: RESTORED (Codex CLI cache)

stdout | test/index.test.ts > OpenAIOAuthPlugin persistAccountPool > preserves flagged organization identity during verify-flagged restore for cached and refreshed paths
[2/2] refresh@example.com: RESTORED

stdout | test/index.test.ts > OpenAIOAuthPlugin persistAccountPool > preserves flagged organization identity during verify-flagged restore for cached and refreshed paths

Results: 2 restored, 0 still flagged


✓ test/index.test.ts (106 tests) 487ms
✓ exports event handler 399ms
✓ test/paths.test.ts (28 tests) 12ms
✓ test/audit.test.ts (17 tests) 90ms
✓ test/config.test.ts (20 tests) 4ms
✓ test/auth-rate-limit.test.ts (22 tests) 11ms
✓ test/health.test.ts (13 tests) 11ms
✓ test/codex.test.ts (32 tests) 6ms
✓ test/context-overflow.test.ts (21 tests) 29ms
✓ test/rate-limit-backoff.test.ts (21 tests) 8ms
✓ test/shutdown.test.ts (11 tests) 76ms
✓ test/parallel-probe.test.ts (15 tests) 232ms
✓ test/utils.test.ts (24 tests) 18ms
✓ test/beginner-ui.test.ts (12 tests) 4ms
✓ test/recovery-constants.test.ts (7 tests) 9ms
✓ test/table-formatter.test.ts (8 tests) 4ms
✓ test/auth-menu.test.ts (2 tests) 6ms
✓ test/ui-format.test.ts (4 tests) 4ms
✓ test/retry-budget.test.ts (4 tests) 3ms
✓ test/oauth-server.integration.test.ts (5 tests) 60ms
✓ test/ui-theme.test.ts (5 tests) 4ms
✓ test/ui-runtime.test.ts (3 tests) 3ms
✓ test/plugin-config.test.ts (61 tests) 23ms
✓ test/schemas.test.ts (60 tests) 26ms
✓ test/auth.test.ts (41 tests) 21ms
✓ test/index-retry.test.ts (1 test) 336ms
✓ waits and retries when all accounts are rate-limited 335ms
✓ test/storage-async.test.ts (23 tests) 30ms
✓ test/rotation-integration.test.ts (21 tests) 23ms
✓ test/accounts.test.ts (99 tests) 20ms
✓ test/copy-oauth-success.test.ts (2 tests) 33ms
✓ test/audit.race.test.ts (1 test) 162ms
✓ test/property/setup.test.ts (3 tests) 8ms
✓ test/property/transformer.property.test.ts (17 tests) 35ms
✓ test/property/rotation.property.test.ts (16 tests) 67ms
✓ test/storage.test.ts (94 tests) 1312ms
✓ returns migrated data even when save fails (line 422-423 coverage) 366ms
✓ throws after 5 failed EPERM retries 503ms
✓ test/chaos/fault-injection.test.ts (43 tests) 58ms
✓ test/fetch-helpers.test.ts (73 tests) 1729ms
✓ transforms request when parsedBody is provided even if init.body is not a string 1688ms
✓ test/request-transformer.test.ts (153 tests) 8635ms
✓ preserves existing prompt_cache_key passed by host (OpenCode) 2357ms

Test Files 56 passed (56)
Tests 1776 passed (1776)
Start at 11:14:37
Duration 9.84s (transform 8.73s, setup 0ms, import 24.66s, tests 14.63s, environment 6ms)

Loading