179 Commits
Author SHA1 Message Date
Tam Nhu Tran eddc404f24 docs: refresh hardening inventory and add 75% quota test 2026-08-25 16:13:41 -04:00
Tam Nhu Tran 745cb74318 fix(cliproxy): make formatQuotaBar pure ASCII and add doctor quota tests 2026-08-25 16:04:33 -04:00
Tam Nhu Tran eca266ad30 feat(cliproxy): clarify quota percentages are remaining in CLI output
Closes #1714
2026-08-25 15:35:23 -04:00
Tam Nhu Tran 1a80717f99 fix(bar): harden lifecycle process handling 2026-08-08 21:17:51 -04:00
poomscandClaude Fable 5 d27b53f235 fix(bar): keep sticky port across ccs bar stop via launch.json fallback
`ccs bar stop` deletes bar.json, so a bar.json-only sticky port is lost on
every stop/start cycle: the next launch reverted to 3000 and the probe could
no longer find a server still running on the previously chosen port.
resolveBarPort now falls back to the --port recorded in launch.json (written
by launch, not deleted by stop), which restores both the sticky port and
probe discovery after a stop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 14:50:18 +07:00
poomscandClaude Fable 5 34608ce291 feat(bar): support --port for ccs bar with sticky port persistence
ccs bar always forced the dashboard onto port 3000 (first free of a
hardcoded candidate list), which collides with other local dev servers, and
bar.json was rewritten to 3000 on every launch.

- `ccs bar [launch] --port N` runs the server on exactly N: reuses a live
  server already on N, moves a running server from another port (SIGTERM via
  server.pid, wait for exit), errors clearly when N is busy or the value is
  invalid.
- The chosen port is persisted into launch.json args, so the Swift app
  self-starts the server on the same port.
- Without --port, launch and serve now try the port recorded in bar.json
  first (sticky), so the server keeps coming back on the port the user last
  chose instead of reverting to 3000.
- Bare flags (`ccs bar --port N`) route to the launch subcommand; --port is
  documented in `ccs bar --help`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 14:09:58 +07:00
Tam Nhu Tran c107a6752c test(cliproxy): cover auto compact windows 2026-07-29 13:46:53 -04:00
Tam Nhu Tran 92fb66c47b test(cliproxy): cover Claude quota probe 429s 2026-07-29 13:22:21 -04:00
Tam Nhu Tran 44718e98ef fix(auth): preserve xAI profile compatibility 2026-07-18 19:04:37 -04:00
minhbi245 54a2b4759b feat(cliproxy): add xAI Grok provider 2026-07-17 00:02:12 +07:00
Kai (Tam Nhu) Tran 3621f8dcb1 fix: validate CCS Bar launch shim target integrity (#1626)
* fix: validate CCS Bar launch shim target integrity

* fix: execute verified bar shim bytes
2026-07-01 00:49:56 -04:00
Kai (Tam Nhu) Tran 0180b62453 fix(bar): use nonce-bound probe auth (#1623) 2026-06-30 13:10:56 -04:00
Kai (Tam Nhu) Tran 396e01ab6f fix: bound bar raw socket probes (#1618) 2026-06-30 12:53:35 -04:00
Kai (Tam Nhu) Tran fb9509d9be fix: make CCS Bar launch descriptor use private shim
Use a private safe ccs.js shim for native CCS Bar launch descriptors so symlinked Bun installs do not fall back to an app environment without node on PATH.
2026-06-23 12:57:33 -04:00
Tam Nhu Tran 239f83df9d test(bar): cover ccs bar install --await-quit relaunch path 2026-06-22 21:07:13 -04:00
Kai (Tam Nhu) Tran 49a7b9dc85 fix(cliproxy): use root URL for Claude provider (#1554)
Built-in Claude provider now uses the CLIProxy root URL instead of /api/provider/claude (which 404'd since base CLIProxy registers /v1/messages at root). Repairs stale local Claude settings, keeps non-Claude providers on their scoped routes, and applies the same root-URL rule to the ccs api create --cliproxy-provider claude bridge path via a shared buildCliproxyProviderPath helper. Closes #1545.
2026-06-16 10:23:48 -04:00
Kai (Tam Nhu) Tran 3fa4a342f9 test(bar): harden bar-probe auth coverage; drop dead proxy shim (#1555)
* test(bar): cover socket-level 401/403 auth detection and liveness-poll rogue rejection

Add two new describe blocks to bar-command.test.ts:

1. `defaultFindRunningServer: socket-level 401/403 classifies authRequired=true`
   Drives `net.connect` via mock.module('net') to verify that status lines
   401 and 403 off the wire set authRequired=true.  A correct-token 200 must
   not set authRequired.  Prior tests bypassed the real status-line parser by
   injecting authRequired via deps; these tests couple to the actual branch.

2. `defaultWaitForServerLive: rogue 200 without matching token is rejected`
   Uses the same net mock pattern to verify that a 200 carrying a wrong
   x-ccs-bar-token never causes the liveness poll to resolve (rogue reflector
   cannot pass).  Correct token resolves immediately.

Export `defaultWaitForServerLive` from launch-subcommand.ts so the direct
unit test can import it without forcing a full handleBarLaunch invocation.

Both test groups are behavior-coupled: removing the relevant branch in
production causes the tests to fail (verified under mutation).

* refactor(bar): drop dead ensureLoopbackNoProxy proxy shim

The probe now uses raw net.connect() which never consults proxy env vars
(undici was fully removed in an earlier PR).  ensureLoopbackNoProxy()
permanently mutated process-wide NO_PROXY/no_proxy on every discovery call
with no effect on the actual network path.

Verified zero remaining references to ensureLoopbackNoProxy outside the
declaration and call site that are now removed.
2026-06-16 09:30:01 -04:00
Kai (Tam Nhu) Tran f25a1015ed fix(bar): authenticate reused local server probes (#1546)
Closes a spoofed-loopback-200 bar.json poisoning vector with a per-user 0600 capability token. The real bar server echoes its file-derived token on /bar/* responses; the launch probe verifies the echoed token against the locally-read file (fail-closed) before reusing a server, so a rogue loopback process that cannot read the token file is rejected.
2026-06-16 09:08:21 -04:00
Kai (Tam Nhu) Tran c0409862d2 fix: handle auth-protected bar launch probes (#1551)
Raw-socket probe detects auth-protected (401/403) bar servers, reuses them, and kills the orphaned detached server on auth timeout. Integrated with the non-blocking priority probe.
2026-06-16 08:45:41 -04:00
Kai (Tam Nhu) Tran 8bd289bfae fix(bar): avoid blocking on lower-priority probes (#1548)
Bar server probing no longer blocks on lower-priority probes.
2026-06-16 08:28:15 -04:00
Kai (Tam Nhu) Tran c776e18434 fix(bar): preserve Gatekeeper quarantine on install (#1534)
Preserves the Gatekeeper quarantine attribute on the installed CCS Bar app so the user makes the right-click to Open trust decision, instead of silently clearing it.
2026-06-15 23:28:24 -04:00
Kai (Tam Nhu) Tran e3566ed765 fix: avoid echoing invalid channel token values (#1542)
Avoids echoing invalid channel token values in config output.
2026-06-15 23:24:42 -04:00
Kai (Tam Nhu) Tran d2848d3931 fix(bar): verify CCS Bar release archive digest (#1532)
Verifies the GitHub release asset sha256 digest before extracting the CCS Bar archive.
2026-06-15 23:12:49 -04:00
Tam Nhu Tran b5ef06a4d5 feat(bar): run the CCS server detached with serve/stop/status
ccs bar now spawns the web-server as a detached background process and
exits immediately instead of hosting it in the foreground, so closing the
terminal no longer takes the bar offline. Adds 'bar serve' (the long-lived
host), 'bar stop', and 'bar status', and records ~/.ccs/bar/launch.json at
install so the app can start the server without a shell PATH.

Refs #1526
2026-06-15 17:13:47 -04:00
Tam Nhu Tran 3aab14ca85 fix(bar): correct the already-running reinstall hint
'open -a' only activates a running app, so suggesting 'ccs bar' as an
alternative to quitting could not load the new binary. The hint now
says to quit from the menu bar first, then run 'ccs bar' to relaunch
the updated app.
2026-06-10 15:25:55 -04:00
Tam Nhu Tran cf3bd8a5ef fix(bar): stage downloads and swap so reinstall never strands the user
The reinstall guard deleted the existing bundle before download, so a
transient download or extraction failure left no app on disk. The
archive now extracts into a hidden staging directory inside the
Applications folder; the old bundle is removed only after the new one
is verified in staging, then renamed into place. Every failure before
the swap leaves the previous install untouched, and staging is cleaned
up on all paths.
2026-06-10 14:09:28 -04:00
Tam Nhu Tran f68c08ede3 fix(bar): verify server compat before Gatekeeper steps and harden reinstall
Three review/CI corrections to the install flow:

The compat handshake now runs before the quarantine-clear and launch
block. It is a server-side check unrelated to Gatekeeper, and the
previous ordering let a failed quarantine clear (always the case where
xattr is absent, e.g. Linux CI) skip the handshake entirely.

Reinstalls remove the existing bundle before extraction so the
post-extraction existence check actually proves the fresh bundle
landed; an unremovable bundle aborts install instead of extracting
over it.

Declining the launch prompt now prints the same run-ccs-bar hint as
the non-TTY path instead of ending silently. Install tests inject the
newer deps (clearQuarantine, isBarRunning, promptLaunch) everywhere
the defaults could touch host binaries, keeping results identical on
macOS and Linux runners.
2026-06-10 13:59:08 -04:00
Tam Nhu Tran 015cc4dd32 fix(bar): stop install at the manual step when quarantine clearing fails
A failed quarantine clear previously fell through to the launch
handoff, so a default-yes prompt (or --launch) opened the still
quarantined app straight into the Gatekeeper block. Install now ends
after printing the manual xattr guidance, with a hint to run 'ccs bar'
once quarantine is cleared; --launch does not override a failed clear.
2026-06-10 13:42:52 -04:00
Tam Nhu Tran dfc8b7d1dc fix(bar): harden install handoff per review
Pin xattr and pgrep to absolute /usr/bin paths so quarantine clearing
and process detection cannot be hijacked through a caller-controlled
PATH. Gate the launch prompt on stdin being a TTY instead of stdout, so
piping install output through tee no longer silently skips the
handoff. Detect an already-running CCS Bar via pgrep before prompting:
a running instance gets a quit-and-reopen hint instead of a redundant
launch prompt, while --launch still proceeds explicitly.
2026-06-10 13:36:35 -04:00
Tam Nhu Tran 4eef3f77a4 feat(bar): one-flow install with quarantine automation and launch handoff
'ccs bar install' previously ended with two manual steps: clearing the
Gatekeeper quarantine by hand and running 'ccs bar' separately.

Install now detects an existing installation and says so before
reinstalling, clears the quarantine attribute itself via execFile with
a graceful fallback to the printed hint when xattr fails, and ends with
a TTY-aware 'Launch CCS Bar now?' prompt (default yes) that hands off
to the existing launch flow. --launch forces the handoff and
--no-launch suppresses it for scripted installs; non-TTY runs skip the
prompt and print the manual command instead.

Closes #1504
2026-06-10 13:25:07 -04:00
Tam Nhu Tran 2fd90fff9b perf(bar): probe reuse candidates concurrently to avoid launch stalls
Sequential probing of up to 10 loopback targets at 1.5s timeout each
could stall 'ccs bar' for ~15s when a non-CCS service occupied a
candidate port without answering. All probes now run concurrently and
the first success in priority order (bar.json port first, IPv4 before
IPv6 per port) is selected, bounding detection at roughly one probe
timeout.
2026-06-10 12:57:39 -04:00
Tam Nhu Tran 3569297b6d fix(bar): probe IPv6 loopback when detecting a running CCS server
'ccs config' starts the web-server on host 'localhost', which macOS
resolves to ::1, so a reuse probe limited to 127.0.0.1 missed the most
common already-running server and launch started a redundant second
instance. Each candidate port is now probed on 127.0.0.1 first and then
[::1]; an IPv6 hit writes the bracketed-literal baseUrl into bar.json,
which URLSession in the Swift app resolves correctly.
2026-06-10 12:04:10 -04:00
Tam Nhu Tran af1a2a0f5d fix(bar): reuse a running CCS web-server and probe ports on the bind host
'ccs bar' always tried to start its own web-server. With a CCS server
already listening on 127.0.0.1:3000, get-port (probing the unspecified
address, which macOS allows to bind alongside a specific loopback
listener) reported 3000 as free, and the subsequent 127.0.0.1 bind
failed with EADDRINUSE, aborting launch.

Launch now probes candidate ports (bar.json port first, then the
default list) with a short-timeout GET /api/bar/summary and reuses the
first live CCS server it finds; only when none responds does it start a
new server. The get-port probe also passes host 127.0.0.1 so the
availability check matches the actual bind target. Probe failures are
treated as no-server-found and never break launch.

Closes #1500
2026-06-10 11:09:41 -04:00
Tam Nhu Tran c572d9f860 fix(bar): read app version from Info.plist and verify bar API instead of version majors
The floating ccs-bar-latest release tag carries no version, so deriving the
app version from tag_name printed 'vccs-bar-latest' and pinned that literal
string. The version now comes from CFBundleShortVersionString in the
extracted bundle's Info.plist; an unreadable plist skips pinning and clears
any stale pin.

The post-install check compared app semver major against the CCS server
major, but the app is versioned independently of the CLI, so the mismatch
warning fired on every install. It is now a capability handshake against
GET /api/bar/summary: 200 confirms the server serves the bar API, 404 warns
the server predates CCS Bar, and anything else keeps the soft warning.
Install never hard-fails on the handshake.

Closes #1497
2026-06-10 00:11:29 -04:00
Tam Nhu Tran 7d3a11a452 fix(bar): resolve pre-dev review findings (security gate, honesty, correctness)
Gate /api/bar/* behind the localhost-when-auth-disabled guard (single DRY
choke point) so native quota/tier/cost can't leak on a non-loopback bind with
auth disabled; add a guard test. Delete the dishonest maxRedirections test that
asserted the opposite of the production redirect hardening. Key per-account
today-cost on the local day (matching analytics) instead of UTC. Stop the
inner 429 retry in the Claude usage fetch so the outer cache + circuit breaker
honor Retry-After. Narrow the usage-transformer map type and fix stale
doc-comments; clarify the one-alert-per-reset-window quota rule; gitignore the
local demo scaffolding.
2026-06-09 18:04:31 -04:00
Tam Nhu Tran 63d10cb2d0 fix(cli): harden ccs bar install + align launch path
Resolve the app path via os.homedir() in launch to match install/uninstall;
validate the host on every redirect hop (manual follow, not blind
maxRedirections); reject zip-slip entries before extracting into ~/Applications.
2026-06-07 16:38:08 -04:00
Tam Nhu Tran 205c2f3cd6 feat(cli): add ccs bar command for the macOS menu bar app
Add ccs bar (install/launch/uninstall/version) and the ~/.ccs/bar.json
discovery handshake the app reads. install resolves a floating release asset,
follows redirects, validates the download host over HTTPS, checks status,
verifies the extracted app, and runs a real version-compat handshake against
/api/overview.
2026-06-07 15:32:51 -04:00
Kai (Tam Nhu) Tran dce968fdf7 Merge pull request #1425 from kaitranntt/codex/fix-unvalidated-codex-quota-labels
fix(cliproxy): sanitize Codex quota labels
2026-05-30 16:12:22 -04:00
Kai (Tam Nhu) Tran e2d487883f Merge pull request #1430 from kaitranntt/codex/fix-vulnerability-in-shell-completion-scripts
fix: avoid relative completion backend execution
2026-05-30 16:12:15 -04:00
Kai (Tam Nhu) Tran e7db1d65f5 Merge pull request #1452 from kaitranntt/codex/propose-fix-for-codex-target-rejection
Mark Codex as a persisted target and align UI/validation
2026-05-30 16:12:03 -04:00
Kai (Tam Nhu) Tran 41e550e92f Merge pull request #1428 from kaitranntt/codex/propose-fix-for-symlinked-cleanup-issue
fix: reject symlinked cleanup directories
2026-05-30 16:05:05 -04:00
Kai (Tam Nhu) Tran 93756489a5 Merge pull request #1434 from kaitranntt/codex/fix-unbounded-recursion-in-receipt-generation
fix(persist): bound Codex translator receipt scan
2026-05-30 15:46:29 -04:00
Tam Nhu Tran f93cb36da6 fix: surface cleanup directory read errors 2026-05-30 15:40:31 -04:00
Tam Nhu Tran a0870aa404 fix(cliproxy): fall back from invalid Codex feature labels 2026-05-30 15:38:50 -04:00
Kai (Tam Nhu) Tran f815db391d Merge pull request #1308 from simonsmh/feat/add-qoder-provider
feat(cliproxy): Qoder provider
2026-05-30 15:35:55 -04:00
Kai (Tam Nhu) Tran 5da6334736 fix(persist): bound Codex translator receipt scan 2026-05-30 15:20:22 -04:00
Kai (Tam Nhu) Tran 4f2dd70b8c fix: avoid relative completion backend execution 2026-05-30 15:19:59 -04:00
Kai (Tam Nhu) Tran 04dc97aaa4 fix: persist codex target selections 2026-05-30 14:57:07 -04:00
Kai (Tam Nhu) Tran 920fba7e13 fix: reject symlinked cleanup directories 2026-05-30 14:53:59 -04:00
Kai (Tam Nhu) Tran 457412277b fix(cliproxy): sanitize Codex quota labels 2026-05-30 14:53:53 -04:00