spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

Add GitHub API caching to prevent rate limitingBrowse files
- Create GitHub API caching script that handles authenticated and unauthenticated requests
- Update Dockerfile to include the script in the container
- Update init-firewall.sh to use cached GitHub API data
- Modify devcontainer.json to run cache script before build and mount cache directory

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Ben Mann authored on Mar 11, 2025 parent 555b6b5 · commit bc84d5711b3f
4 changed files+130 -13compared with 555b6b5
M.devcontainer/Dockerfile
A.devcontainer/cache-github-api.sh
M.devcontainer/devcontainer.json
M.devcontainer/init-firewall.sh
@@ -69,10 +69,10 @@
6969 # Install Claude
7070 RUN npm install -g @anthropic-ai/claude-code
7171
72-# Copy and set up firewall script
73-COPY init-firewall.sh /usr/local/bin/
72+# Copy and set up scripts
73+COPY init-firewall.sh cache-github-api.sh /usr/local/bin/
7474 USER root
75-RUN chmod +x /usr/local/bin/init-firewall.sh && \
75+RUN chmod +x /usr/local/bin/init-firewall.sh /usr/local/bin/cache-github-api.sh && \
7676 echo "node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/node-firewall && \
7777 chmod 0440 /etc/sudoers.d/node-firewall
7878 USER node
@@ -1,0 +1,109 @@
1+#!/bin/bash
2+set -e
3+
4+# Script to cache GitHub API data
5+# Used to prevent rate limiting during container builds
6+
7+# Configuration
8+# Store cache in the home directory
9+CACHE_DIR="${HOME}/.github-meta-cache"
10+CACHE_FILE="${CACHE_DIR}/meta.json"
11+TIMESTAMP_FILE="${CACHE_DIR}/meta-timestamp.txt"
12+MAX_AGE_SECONDS=3600 # Cache expires after 1 hour
13+
14+# Create cache directory if it doesn't exist
15+mkdir -p "${CACHE_DIR}"
16+
17+# Function to get current timestamp
18+get_timestamp() {
19+ date +%s
20+}
21+
22+# Function to check if cache is valid
23+is_cache_valid() {
24+ if [[ ! -f "${CACHE_FILE}" || ! -f "${TIMESTAMP_FILE}" ]]; then
25+ return 1
26+ fi
27+
28+ local cache_time=$(cat "${TIMESTAMP_FILE}")
29+ local current_time=$(get_timestamp)
30+ local age=$((current_time - cache_time))
31+
32+ if [[ ${age} -gt ${MAX_AGE_SECONDS} ]]; then
33+ echo "Cache is expired (${age} seconds old)"
34+ return 1
35+ fi
36+
37+ echo "Using cached GitHub API data (${age} seconds old)"
38+ return 0
39+}
40+
41+# Function to fetch data using authenticated gh cli
42+fetch_with_gh() {
43+ echo "Attempting to fetch GitHub API data using authenticated gh CLI..."
44+ if gh auth status &>/dev/null; then
45+ gh api meta > "${CACHE_FILE}" &&
46+ get_timestamp > "${TIMESTAMP_FILE}" &&
47+ echo "Successfully fetched and cached GitHub API data using gh CLI"
48+ return $?
49+ else
50+ echo "gh CLI not authenticated"
51+ return 1
52+ fi
53+}
54+
55+# Function to fetch data using curl
56+fetch_with_curl() {
57+ echo "Attempting to fetch GitHub API data using curl..."
58+ # First try with GITHUB_TOKEN if available
59+ if [[ -n "${GITHUB_TOKEN}" ]]; then
60+ echo "Using GITHUB_TOKEN for authentication"
61+ curl -s -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/meta > "${CACHE_FILE}" &&
62+ get_timestamp > "${TIMESTAMP_FILE}" &&
63+ echo "Successfully fetched and cached GitHub API data using curl with token"
64+ return $?
65+ else
66+ # Fall back to unauthenticated request
67+ echo "No GITHUB_TOKEN found, making unauthenticated request (may be rate limited)"
68+ curl -s https://api.github.com/meta > "${CACHE_FILE}"
69+
70+ # Check if the response indicates rate limiting
71+ if grep -q "API rate limit exceeded" "${CACHE_FILE}"; then
72+ echo "Rate limit exceeded for unauthenticated request"
73+ return 1
74+ else
75+ get_timestamp > "${TIMESTAMP_FILE}"
76+ echo "Successfully fetched and cached GitHub API data using curl without auth"
77+ return 0
78+ fi
79+ fi
80+}
81+
82+# Main logic
83+if is_cache_valid; then
84+ echo "Using existing cache from $(cat ${TIMESTAMP_FILE})"
85+ exit 0
86+fi
87+
88+# Try with gh CLI first
89+if ! fetch_with_gh; then
90+ # Fall back to curl
91+ if ! fetch_with_curl; then
92+ # Both methods failed, check if we have an existing cache file
93+ if [[ -f "${CACHE_FILE}" ]]; then
94+ echo "Warning: Failed to update cache, using existing cached data (which may be expired)"
95+ exit 0
96+ else
97+ echo "Error: Failed to fetch GitHub API data and no cache exists"
98+ exit 1
99+ fi
100+ fi
101+fi
102+
103+# Display a summary of the cached data
104+echo "GitHub API meta data cached successfully. Summary:"
105+jq -r '.domains.actions | length' "${CACHE_FILE}" > /dev/null 2>&1 &&
106+ echo "- Actions domains: $(jq -r '.domains.actions | length' "${CACHE_FILE}")" ||
107+ echo "- Could not parse actions domains from cache file"
108+
109+exit 0
@@ -4,6 +4,9 @@
44 "dockerfile": "Dockerfile",
55 "args": {
66 "TZ": "${localEnv:TZ:America/Los_Angeles}"
7+ },
8+ "prebuild": {
9+ "command": "bash -c '${localWorkspaceFolder}/.devcontainer/cache-github-api.sh || echo \"Warning: Failed to cache GitHub API data\"'"
710 }
811 },
912 "runArgs": [
@@ -39,7 +42,8 @@
3942 "remoteUser": "node",
4043 "mounts": [
4144 "source=claude-code-bashhistory,target=/commandhistory,type=volume",
42- "source=claude-code-config,target=/home/node/.claude,type=volume"
45+ "source=claude-code-config,target=/home/node/.claude,type=volume",
46+ "type=bind,source=${localEnv:HOME}/.github-meta-cache,target=/github-meta-cache,consistency=cached"
4347 ],
4448 "remoteEnv": {
4549 "NODE_OPTIONS": "--max-old-space-size=4096",
@@ -27,16 +27,20 @@
2727 # Create ipset with CIDR support
2828 ipset create allowed-domains hash:net
2929
30-# Fetch GitHub meta information and aggregate + add their IP ranges
31-echo "Fetching GitHub IP ranges..."
32-gh_ranges=$(curl -s https://api.github.com/meta)
33-if [ -z "$gh_ranges" ]; then
34- echo "ERROR: Failed to fetch GitHub IP ranges"
35- exit 1
36-fi
30+# Use cached GitHub meta information from mounted volume
31+CACHE_FILE="/github-meta-cache/meta.json"
3732
38-if ! echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null; then
39- echo "ERROR: GitHub API response missing required fields"
33+echo "Using cached GitHub IP ranges..."
34+if [ -f "${CACHE_FILE}" ]; then
35+ gh_ranges=$(cat "${CACHE_FILE}")
36+
37+ # Verify the cached data is valid
38+ if ! echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null; then
39+ echo "ERROR: Cached GitHub API data is invalid"
40+ exit 1
41+ fi
42+else
43+ echo "ERROR: No cached GitHub IP ranges found"
4044 exit 1
4145 fi
4246