* fix: pin all GitHub Actions to commit SHAs and version-lock tools
Addresses supply chain hardening findings from issue #2982:
- Pin all 6 GitHub Actions to full commit SHAs with version comments:
- actions/checkout@v4 → SHA 34e1148...
- oven-sh/setup-bun@v2 → SHA 0c5077e...
- actions/github-script@v7 → SHA f28e40c...
- docker/login-action@v3 → SHA c94ce9f...
- docker/build-push-action@v6 → SHA 10e90e3...
- hashicorp/setup-packer@main → SHA c3d53c5... (v3.2.0)
- Pin Packer version: latest → 1.15.0 (in packer-snapshots.yml)
- Pin bun version: latest → 1.3.11 (in agent-tarballs.yml)
- Pin shellcheck: replace apt-get (no version) with pinned download
of v0.10.0 from GitHub releases with SHA256 integrity check
These changes eliminate the primary LiteLLM-style attack vector:
a compromised action maintainer can no longer force-push malicious
code to an existing tag and have it run in CI.
Fixes#2982
Agent: issue-fixer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: exclude import aliases from no-type-assertion lint rule
The `JsNamedImportSpecifier` exclusion prevents `import { foo as bar }`
patterns from being flagged as type assertions. Previously, any `as`
keyword in import/export statements triggered the ban because the GritQL
pattern `$value as $type` matched import specifiers as well as actual
TypeScript type assertions.
This also removes the `as _foo` import aliases in the script-failure-guidance
test file (replaced with direct imports + distinctly-named wrapper functions)
which were the original manifestation of this bug.
All 1944 tests pass. Biome check clean across 169 files.
Agent: issue-fixer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
The original bunfig.toml used `line` and `function` (singular) which Bun
silently ignores. The correct field names are `lines` and `functions` (plural).
Changes:
- Fix field names: line→lines, function→functions
- Set thresholds: lines=0.35 (floor: digitalocean.ts 38.5%), functions=0.5
(floor: preload.ts 50%)
- Add coverageSkipTestFiles=true
- Keep --coverage in CI (bunfig thresholds enforce exit code on failure)
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: L <6723574+louisgv@users.noreply.github.com>
- Move bunfig.toml to repo root with valid coverageThreshold syntax
(line=80%, function=0 to avoid per-file false positives)
- Add --coverage flag to CI test step
- Delete packages/cli/bunfig.toml (superseded by root config)
- Add tests for packages/shared (type-guards, parse, result)
- Colocate billing config into each cloud directory (aws/billing.ts,
gcp/billing.ts, hetzner/billing.ts, digitalocean/billing.ts)
- Refactor billing-guidance.ts: BillingConfig interface replaces
cloud-string-keyed Record maps
- Bump CLI version to 0.25.1
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: L <6723574+louisgv@users.noreply.github.com>
* ci: add Mock Tests job to satisfy required status check
Split the unit-tests job into mock-tests (runs bun test) and unit-tests
(verifies cloud bundles build). The repo ruleset requires "Mock Tests",
"Unit Tests", and "Biome Lint" checks — the missing "Mock Tests" job was
blocking all PR merges.
Fixes#1901
Agent: issue-fixer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* style: fix pre-existing Biome format issues in 9 files
Auto-applied Biome formatter to src/ to resolve failing "Biome Lint"
required status check. No logic changes — formatting only.
Agent: issue-fixer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Restructure the repo as a Bun workspace monorepo:
- Move cli/ → packages/cli/
- Create packages/shared/ (@openrouter/spawn-shared) with type-guards and parse utilities
- Add root package.json with workspace configuration
- Update all CLI imports to use @openrouter/spawn-shared
- Deduplicate toRecord/toObjectArray helpers from 4 cloud modules
- Update SPA (slack-bot) to use shared package instead of local toObj()
- Update 48 agent shell scripts for new packages/cli/ path
- Update install.sh, install.ps1, e2e, and test scripts
- Update all GitHub workflows, .gitignore, pre-commit hooks
- Update CLAUDE.md, README.md, and skill prompt references
- Pin all dependency versions (no ^ ranges)
- Bump CLI version 0.9.1 → 0.10.0
All 1908 tests pass. Lint clean. All 8 cloud bundles build.
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
shared/common.sh (3852 lines) was dead code — the entire architecture
was rewritten to TypeScript in cli/src/. No agent scripts source it
anymore. The only consumer was github-auth.sh which just needed 4
log functions (now inlined).
Remove 27 test files that spawned ~800+ real bash/bun subprocesses per
run (the root cause of slow bun test). Every shared-common-*.test.ts
file forked a real bash shell per test case to source shared/common.sh.
CLI subprocess tests spawned `bun run index.ts` per assertion. These
were integration tests, not unit tests.
Also removes:
- mock-tests CI job from test.yml (ran test/mock.sh which opens browser)
- Stale plan files referencing deleted infrastructure
- All CLAUDE.md/README.md references to the old lib/common.sh pattern
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move all fly TypeScript files from fly/lib/*.ts and fly/main.ts into
cli/src/fly/. This gives them access to cli/node_modules (@clack/prompts),
biome linting, and the existing bun:test infrastructure — no symlinks or
NODE_PATH hacks needed.
The org picker now uses @clack/prompts select() directly (static import,
bundled at build time).
New: cli/build-clouds.sh — auto-discovers cli/src/*/main.ts and bundles
each into {cloud}.js. Scalable to future cloud TS migrations:
bash cli/build-clouds.sh # build all
bash cli/build-clouds.sh fly # build one
Shims now check for cli/src/fly/main.ts (local) or download fly.js from
GitHub releases (remote curl|bash).
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): propagate mock test exit code and fix broken pipe in summary
The test workflow had three issues:
- mock.sh exit code was swallowed by tee (no pipefail), so the check
always passed even with 165 failures
- grep|head pipe caused "write error: Broken pipe" in post summary
- Summary was noisy with 100+ individual result lines
Now uses PIPESTATUS[0] to capture the real exit code, shows a clean
results line plus collapsible failures list, and fails the check when
tests fail.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ci): report test results without blocking PRs
Pre-existing failures (165) shouldn't block unrelated PRs. The summary
still shows pass/fail counts and a collapsible failures list so the bot
can see the results.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* perf(ci): increase QA cycle frequency from daily to every 4 hours
Daily runs meant breakage could go undetected for up to 24 hours.
Every 4 hours gives 6 runs/day (00:00, 04:00, 08:00, 12:00, 16:00,
20:00 UTC) with a max 4-hour feedback loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ci): add missing Check results step to fail on test errors
Addresses review feedback:
- The exit code was captured via PIPESTATUS[0] into GITHUB_OUTPUT but
no subsequent step consumed it, so the workflow always passed even
when tests failed. Added a "Check results" step that reads the
captured exit code and fails the job accordingly.
- Reverted QA cron schedule change (every 4 hours back to daily at
06:00 UTC) as it was unrelated to the test exit code fix and should
be proposed separately if desired.
Agent: pr-maintainer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
* fix: strip ANSI colors before grepping test summary
The mock test output uses ANSI escape codes for colored ✓/✗/━━━
characters, so the grep in the Post summary step couldn't match
them. Strip colors with sed first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use NO_COLOR standard instead of sed to strip ANSI codes
mock.sh now respects the NO_COLOR env var (https://no-color.org/).
CI sets NO_COLOR=1 so grep matches ✓/✗/━━━ cleanly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Runs `bash test/mock.sh` on every pull request targeting main.
Includes concurrency grouping to cancel stale runs and a 10-minute
timeout. Results are posted to the GitHub Actions step summary.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>