Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5a030d0
feat(providers): add Vertex AI provider type
itdove Apr 6, 2026
dc36903
docs: clarify that cluster:build:full also starts the gateway
itdove Apr 6, 2026
a6cc6a4
docs: add Vertex AI provider to inference and provider docs
itdove Apr 6, 2026
17bf434
feat(vertex): implement GCP OAuth authentication for Vertex AI
itdove Apr 6, 2026
5ac42ba
fix(vertex): use separate thread for OAuth token generation
itdove Apr 6, 2026
f606dc3
feat(scripts): improve cleanup script with sandbox deletion and bette…
itdove Apr 6, 2026
d36e58b
feat(sandbox): inject Vertex AI credentials as actual environment var…
itdove Apr 6, 2026
2dd3438
feat(vertex): auto-inject CLAUDE_CODE_USE_VERTEX for claude CLI
itdove Apr 7, 2026
bc3342d
feat(podman): increase default memory to 12 GB for better build perfo…
itdove Apr 7, 2026
b08de19
fix(scripts): update CLI installation command in setup script
itdove Apr 7, 2026
b56828e
fix(router): remove model field from Vertex AI request bodies
itdove Apr 7, 2026
308dc5c
docs: add Vertex AI example with network policy
itdove Apr 7, 2026
83a94b9
fix(build): handle Podman --push flag and array expansion
itdove Apr 7, 2026
b2d6545
feat(build): add Podman multi-arch support to docker-publish-multiarc…
itdove Apr 7, 2026
8a27b2f
fix: apply cargo fmt formatting to vertex provider
itdove Apr 7, 2026
8241dc7
refactor: remove OAuth token storage from Vertex provider
itdove Apr 7, 2026
987b2a0
docs(vertex): improve ADC detection and troubleshooting docs
itdove Apr 7, 2026
c58f3c7
style(vertex): apply cargo fmt formatting
itdove Apr 7, 2026
c6a63ea
fix(docker): resolve DNF package dependency conflict in cluster build
itdove Apr 8, 2026
a3afb41
feat(vertex): implement OAuth auto-refresh with proxy-based header in…
itdove Apr 9, 2026
edc7523
feat(oauth): implement policy-based OAuth auto-refresh configuration
itdove Apr 9, 2026
64ea08e
refactor(oauth): implement generic policy-driven OAuth header injection
itdove Apr 9, 2026
ad39abe
style: apply cargo fmt to OAuth tests
itdove Apr 9, 2026
a91fb49
docs(oauth): update OAUTH_PROVIDERS.md for policy-based architecture
itdove Apr 9, 2026
e112671
fix(test): update test to expect error for unsolicited 101 upgrade
itdove Apr 9, 2026
f8ebb46
fix(test): refactor resolve_provider_environment to avoid Kubernetes …
itdove Apr 10, 2026
0ab700f
style: apply cargo fmt formatting
itdove Apr 10, 2026
3c9c6ca
refactor(sandbox): extract Vertex OAuth interception to provider module
itdove Apr 10, 2026
cf18042
chore: merge midstream to resolve conflicts
itdove Apr 10, 2026
d390a79
refactor(scripts): address PR #22 review feedback
itdove Apr 10, 2026
7b43617
fix(sandbox): filter OAuth credentials from agent process environment
itdove Apr 10, 2026
5a95f3f
fix(sandbox): prevent OAuth credentials from leaking to SSH sessions
itdove Apr 10, 2026
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
8 changes: 8 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"Bash(cargo build:*)",
"Bash(cargo test:*)"
]
}
}
60 changes: 60 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,66 @@ These pipelines connect skills into end-to-end workflows. Individual skill files
- Bollard (the Rust Docker client library) connects to Podman via its Docker-compatible API — no separate Podman client is needed.
- When referencing host gateway aliases, use both `host.docker.internal` and `host.containers.internal` for cross-runtime compatibility.

### Debugging with Podman

When using Podman (especially on macOS where Podman runs in a VM), debugging requires accessing the Podman machine:

**Accessing the Podman VM:**
```bash
podman machine ssh
```

**Common debugging commands:**
```bash
# Check cluster logs via kubectl (inside podman machine or via ssh)
podman machine ssh -- "podman exec openshell-cluster-openshell kubectl logs -n openshell <pod-name>"

# Check running containers
podman machine ssh -- "podman ps -a"

# Check images and timestamps
podman machine ssh -- "podman images"

# Verify binary in cluster
podman machine ssh -- "podman exec openshell-cluster-openshell ls -lh /opt/openshell/bin/openshell-sandbox"

# Check for specific strings in binary
podman machine ssh -- "podman exec openshell-cluster-openshell strings /opt/openshell/bin/openshell-sandbox | grep <pattern>"

# Get sandbox pod logs
podman machine ssh -- "podman exec openshell-cluster-openshell kubectl logs -n openshell <sandbox-name> --container agent --tail 100"
```

**Important: Cross-compilation requirement**

Running `cargo build --release` on macOS produces a macOS binary, not a Linux binary. The cluster runs Linux containers, so using a macOS binary causes "exec format error".

- ✅ **Correct:** Use `mise run cluster:build:full` which handles cross-compilation
- ❌ **Incorrect:** `cargo build --release` then manually copying the binary

**Fast iteration workflow:**

After modifying Rust code in `crates/openshell-sandbox/`:

```bash
# Force clean rebuild to avoid cargo cache issues
cargo clean -p openshell-sandbox

# Full cluster rebuild (handles cross-compilation)
mise run cluster:build:full

# Recreate sandbox to pick up new binary
openshell sandbox delete <name>
openshell sandbox create --name <name> --provider <provider> --policy <policy> -- bash
```

**Common issues:**

- **"exec format error"**: Binary is for wrong architecture (macOS vs Linux)
- **Binary not updating**: Cargo is using cached artifacts - run `cargo clean -p openshell-sandbox`
- **Empty logs**: `RUST_LOG` environment variable not set in sandbox agent - logs are disabled by default
- **Changes not reflected**: Sandbox was created before cluster rebuild - always recreate sandboxes after deploying new binaries

## Cluster Infrastructure Changes

- If you change cluster bootstrap infrastructure (e.g., `openshell-bootstrap` crate, `deploy/docker/Dockerfile.images`, `cluster-entrypoint.sh`, `cluster-healthcheck.sh`, deploy logic in `openshell-cli`), update the `debug-openshell-cluster` skill in `.agents/skills/debug-openshell-cluster/SKILL.md` to reflect those changes.
Expand Down
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ k8s-openapi = { version = "0.21.1", features = ["v1_26"] }
# IDs
uuid = { version = "1.10", features = ["v4"] }

# Time/Date
chrono = "0.4"

# Async
async-trait = "0.1"

[workspace.lints.rust]
unsafe_code = "warn"
rust_2018_idioms = { level = "warn", priority = -1 }
Expand Down
46 changes: 40 additions & 6 deletions cleanup-openshell-podman-macos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,43 @@ set -e
echo "=== OpenShell Podman Cleanup Script ==="
echo ""

# Delete all sandboxes first (before destroying gateway)
echo "Deleting all sandboxes..."
if command -v openshell &>/dev/null; then
# Get list of sandboxes and delete each one
openshell sandbox list --no-header 2>/dev/null | awk '{print $1}' | while read -r sandbox; do
if [ -n "$sandbox" ]; then
echo " Deleting sandbox: $sandbox"
openshell sandbox delete "$sandbox" 2>/dev/null || true
fi
done
fi

# Destroy OpenShell gateway (if it exists)
echo "Destroying OpenShell gateway..."
if command -v openshell &>/dev/null; then
openshell gateway destroy --name openshell 2>/dev/null || true
fi

# Stop and remove any running OpenShell containers
echo "Stopping OpenShell containers..."
podman ps -a | grep openshell | awk '{print $1}' | xargs -r podman rm -f || true
# Stop and remove cluster container
echo "Stopping cluster container..."
podman stop openshell-cluster-openshell 2>/dev/null || true
podman rm openshell-cluster-openshell 2>/dev/null || true

# Stop and remove local registry container
echo "Stopping local registry..."
podman stop openshell-local-registry 2>/dev/null || true
podman rm openshell-local-registry 2>/dev/null || true

# Stop and remove any other OpenShell containers
echo "Cleaning up remaining OpenShell containers..."
podman ps -a | grep openshell | awk '{print $1}' | xargs -r podman rm -f 2>/dev/null || true

# Remove OpenShell images
echo "Removing OpenShell images..."
podman images | grep -E "openshell|cluster" | awk '{print $3}' | xargs -r podman rmi -f || true
podman rmi localhost/openshell/cluster:dev 2>/dev/null || true
podman rmi localhost/openshell/gateway:dev 2>/dev/null || true
podman images | grep -E "openshell|127.0.0.1:5000/openshell" | awk '{print $3}' | xargs -r podman rmi -f 2>/dev/null || true

# Remove CLI binary
echo "Removing CLI binary..."
Expand All @@ -41,8 +65,11 @@ rm -rf ~/.openshell
echo "Removing build artifacts..."
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
rm -rf target/
rm -rf deploy/docker/.build/
if command -v cargo &>/dev/null; then
echo " Running cargo clean..."
cargo clean 2>/dev/null || true
fi
rm -rf deploy/docker/.build/ 2>/dev/null || true

# Clean Podman cache
echo "Cleaning Podman build cache..."
Expand All @@ -51,6 +78,13 @@ podman system prune -af --volumes
echo ""
echo "=== Cleanup Complete ==="
echo ""
echo "OpenShell containers, images, and configuration have been removed."
echo ""
echo "To reinstall OpenShell:"
echo " 1. source scripts/podman.env"
echo " 2. mise run cluster:build:full"
echo " 3. cargo install --path crates/openshell-cli --root ~/.local"
echo ""
echo "To completely remove the OpenShell Podman machine:"
echo " podman machine stop openshell"
echo " podman machine rm openshell"
Expand Down
2 changes: 2 additions & 0 deletions crates/openshell-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ enum CliProviderType {
Gitlab,
Github,
Outlook,
Vertex,
}

#[derive(Clone, Debug, ValueEnum)]
Expand Down Expand Up @@ -646,6 +647,7 @@ impl CliProviderType {
Self::Gitlab => "gitlab",
Self::Github => "github",
Self::Outlook => "outlook",
Self::Vertex => "vertex",
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions crates/openshell-core/src/inference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,19 @@ static NVIDIA_PROFILE: InferenceProviderProfile = InferenceProviderProfile {
default_headers: &[],
};

static VERTEX_PROFILE: InferenceProviderProfile = InferenceProviderProfile {
provider_type: "vertex",
// Base URL template - actual URL constructed at request time with project/region/model
default_base_url: "https://us-central1-aiplatform.googleapis.com/v1",
protocols: ANTHROPIC_PROTOCOLS,
// Look for OAuth token first, fallback to project ID (for manual config)
credential_key_names: &["VERTEX_OAUTH_TOKEN", "ANTHROPIC_VERTEX_PROJECT_ID"],
base_url_config_keys: &["VERTEX_BASE_URL", "ANTHROPIC_VERTEX_REGION"],
// Vertex uses OAuth Bearer tokens, not x-api-key
auth: AuthHeader::Bearer,
default_headers: &[("anthropic-version", "vertex-2023-10-16")],
};

/// Look up the inference provider profile for a given provider type.
///
/// Returns `None` for provider types that don't support inference routing
Expand All @@ -95,6 +108,7 @@ pub fn profile_for(provider_type: &str) -> Option<&'static InferenceProviderProf
"openai" => Some(&OPENAI_PROFILE),
"anthropic" => Some(&ANTHROPIC_PROFILE),
"nvidia" => Some(&NVIDIA_PROFILE),
"vertex" => Some(&VERTEX_PROFILE),
_ => None,
}
}
Expand Down Expand Up @@ -176,6 +190,7 @@ mod tests {
assert!(profile_for("openai").is_some());
assert!(profile_for("anthropic").is_some());
assert!(profile_for("nvidia").is_some());
assert!(profile_for("vertex").is_some());
assert!(profile_for("OpenAI").is_some()); // case insensitive
}

Expand Down
Loading
Loading