Skip to content

Commit f4268d3

Browse files
authored
Add Claude Code session start hook to install bazel and ibazel (#1013)
1 parent 02a4c9c commit f4268d3

File tree

5 files changed

+178
-1
lines changed

5 files changed

+178
-1
lines changed

.claude/hooks/session-start.sh

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
# Only run in remote (Claude Code on the web) environments
5+
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
6+
exit 0
7+
fi
8+
9+
INSTALL_DIR="/usr/local/bin"
10+
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
11+
DISTDIR="${PROJECT_DIR}/.bazel-distdir"
12+
13+
mkdir -p "$DISTDIR"
14+
15+
# Install Bazelisk (provides the `bazel` command)
16+
if ! command -v bazel &>/dev/null; then
17+
echo "Installing Bazelisk..."
18+
BAZELISK_VERSION="v1.25.0"
19+
curl -fsSL "https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-amd64" \
20+
-o "${INSTALL_DIR}/bazel"
21+
chmod +x "${INSTALL_DIR}/bazel"
22+
echo "Bazelisk installed successfully"
23+
fi
24+
25+
# Install ibazel (incremental Bazel)
26+
if ! command -v ibazel &>/dev/null; then
27+
echo "Installing ibazel..."
28+
IBAZEL_VERSION="v0.25.3"
29+
curl -fsSL "https://github.com/bazelbuild/bazel-watcher/releases/download/${IBAZEL_VERSION}/ibazel_linux_amd64" \
30+
-o "${INSTALL_DIR}/ibazel"
31+
chmod +x "${INSTALL_DIR}/ibazel"
32+
echo "ibazel installed successfully"
33+
fi
34+
35+
# Create custom Java truststore for Bazel's embedded JDK
36+
# The remote environment uses a TLS-inspecting proxy whose CA is in the system
37+
# trust store but not in Bazel's embedded JDK truststore.
38+
CUSTOM_CACERTS="${DISTDIR}/cacerts"
39+
PROXY_CA="/usr/local/share/ca-certificates/swp-ca-production.crt"
40+
41+
if [ ! -f "$CUSTOM_CACERTS" ] && [ -f "$PROXY_CA" ]; then
42+
echo "Creating custom truststore with proxy CA..."
43+
44+
# Prime Bazel installation to get its embedded JDK
45+
bazel version >/dev/null 2>&1
46+
47+
BAZEL_INSTALL="$(bazel info install_base 2>/dev/null)"
48+
BAZEL_CACERTS="${BAZEL_INSTALL}/embedded_tools/jdk/lib/security/cacerts"
49+
50+
if [ -f "$BAZEL_CACERTS" ]; then
51+
cp "$BAZEL_CACERTS" "$CUSTOM_CACERTS"
52+
keytool -importcert -keystore "$CUSTOM_CACERTS" -storepass changeit \
53+
-noprompt -alias "anthropic-proxy-ca" -file "$PROXY_CA" >/dev/null 2>&1
54+
echo "Custom truststore created with proxy CA"
55+
fi
56+
fi
57+
58+
# Generate user.bazelrc for the remote proxy environment
59+
# - Disable Bzlmod (this project uses WORKSPACE, not MODULE.bazel)
60+
# - Use distdir for pre-downloaded dependencies
61+
# - Enable proxy auth for JDK HTTPS tunneling
62+
# - Use custom truststore with proxy's TLS inspection CA
63+
BAZELRC="${PROJECT_DIR}/user.bazelrc"
64+
if [ ! -f "$BAZELRC" ]; then
65+
cat > "$BAZELRC" << EOF
66+
# Auto-generated by Claude Code session-start hook for remote environments
67+
# This file is gitignored - see .bazelrc try-import
68+
common --noenable_bzlmod
69+
build --distdir=.bazel-distdir
70+
fetch --distdir=.bazel-distdir
71+
query --distdir=.bazel-distdir
72+
73+
# Enable proxy auth for HTTPS tunneling (disabled by default in JDK)
74+
startup --host_jvm_args=-Djdk.http.auth.tunneling.disabledSchemes=
75+
startup --host_jvm_args=-Djdk.http.auth.proxying.disabledSchemes=
76+
77+
# Use custom truststore that includes the proxy's TLS inspection CA
78+
startup --host_jvm_args=-Djavax.net.ssl.trustStore=${DISTDIR}/cacerts
79+
startup --host_jvm_args=-Djavax.net.ssl.trustStorePassword=changeit
80+
EOF
81+
echo "Created user.bazelrc with proxy-friendly settings"
82+
fi
83+
84+
# Pre-download Bazel WORKSPACE dependencies into distdir
85+
"${PROJECT_DIR}/scripts/bazel_fetch_deps.sh"
86+
87+
echo "Session startup complete: bazel and ibazel are available"

.claude/settings.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"hooks": {
3+
"SessionStart": [
4+
{
5+
"hooks": [
6+
{
7+
"type": "command",
8+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"
9+
}
10+
]
11+
}
12+
]
13+
}
14+
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ bazel-out
55
bazel-testlogs
66
bazel-workspace
77
user.bazelrc
8+
.bazel-distdir
89
bdist
910
dist
1011
.vscode/

.golangci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ linters:
1212
- gochecknoinits
1313
- gocyclo
1414
- godox
15-
- modernize
1615
- musttag
1716
- noctx
1817
- noinlineerr

scripts/bazel_fetch_deps.sh

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/bin/bash
2+
# Pre-download Bazel dependencies using curl (which properly handles proxy auth)
3+
# This populates --distdir so Bazel doesn't need to download through proxy
4+
5+
set -e
6+
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
WORKSPACE_DIR="$(dirname "$SCRIPT_DIR")"
9+
DISTDIR="${WORKSPACE_DIR}/.bazel-distdir"
10+
11+
mkdir -p "$DISTDIR"
12+
13+
echo "Downloading Bazel dependencies to $DISTDIR..."
14+
echo "Using proxy: ${HTTP_PROXY:-none}"
15+
16+
# Extract download URLs from WORKSPACE
17+
# Format: urls = ["https://..."]
18+
URLS=$(grep -oE 'https://[^"]+\.(tar\.gz|zip)' "$WORKSPACE_DIR/WORKSPACE" | sort -u)
19+
20+
# Resolve Starlark format strings like {0} by extracting version variables
21+
buildtools_version=$(grep -oP 'buildtools_version = "\K[^"]+' "$WORKSPACE_DIR/WORKSPACE" || true)
22+
if [ -n "$buildtools_version" ]; then
23+
URLS="${URLS//\{0\}/$buildtools_version}"
24+
fi
25+
26+
downloaded=0
27+
skipped=0
28+
failed=0
29+
30+
while IFS= read -r url; do
31+
if [ -z "$url" ]; then
32+
continue
33+
fi
34+
35+
# Skip URLs that still contain unresolved format strings
36+
if [[ "$url" == *"{"* ]]; then
37+
echo "⚠ Skipping unresolved URL: $url"
38+
failed=$((failed + 1))
39+
continue
40+
fi
41+
42+
filename=$(basename "$url")
43+
output_file="$DISTDIR/$filename"
44+
45+
if [ -f "$output_file" ]; then
46+
echo "✓ Already have: $filename"
47+
skipped=$((skipped + 1))
48+
continue
49+
fi
50+
51+
echo "Downloading: $filename"
52+
if curl -f -L --retry 3 -o "$output_file.tmp" "$url" 2>/dev/null; then
53+
mv "$output_file.tmp" "$output_file"
54+
echo "✓ Downloaded: $filename"
55+
downloaded=$((downloaded + 1))
56+
else
57+
echo "✗ Failed: $filename"
58+
rm -f "$output_file.tmp"
59+
failed=$((failed + 1))
60+
fi
61+
done <<< "$URLS"
62+
63+
echo ""
64+
echo "Summary:"
65+
echo " Downloaded: $downloaded"
66+
echo " Skipped (cached): $skipped"
67+
echo " Failed: $failed"
68+
echo " Location: $DISTDIR"
69+
echo ""
70+
if [ "$failed" -eq 0 ]; then
71+
echo "✓ All dependencies downloaded successfully!"
72+
exit 0
73+
else
74+
echo "⚠ Some downloads failed. Bazel may still work with cached/distdir files."
75+
exit 0 # Don't fail the script, downloads may be optional
76+
fi

0 commit comments

Comments
 (0)