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

claude-code / scripts / gh.sh
85 lines · 2.1 KBRaw
1#!/usr/bin/env bash
2set -euo pipefail
3
4# Wrapper around gh CLI that only allows specific subcommands and flags.
5# All commands are scoped to the current repository via GH_REPO or GITHUB_REPOSITORY.
6#
7# Usage:
8# ./scripts/gh.sh issue view 123
9# ./scripts/gh.sh issue view 123 --comments
10# ./scripts/gh.sh issue list --state open --limit 20
11# ./scripts/gh.sh search issues "search query" --limit 10
12# ./scripts/gh.sh label list --limit 100
13
14ALLOWED_FLAGS=(--comments --state --limit --label)
15FLAGS_WITH_VALUES=(--state --limit --label)
16
17SUB1="${1:-}"
18SUB2="${2:-}"
19CMD="$SUB1 $SUB2"
20case "$CMD" in
21 "issue view"|"issue list"|"search issues"|"label list")
22 ;;
23 *)
24 exit 1
25 ;;
26esac
27
28shift 2
29
30# Separate flags from positional arguments
31POSITIONAL=()
32FLAGS=()
33skip_next=false
34for arg in "$@"; do
35 if [[ "$skip_next" == true ]]; then
36 FLAGS+=("$arg")
37 skip_next=false
38 elif [[ "$arg" == -* ]]; then
39 flag="${arg%%=*}"
40 matched=false
41 for allowed in "${ALLOWED_FLAGS[@]}"; do
42 if [[ "$flag" == "$allowed" ]]; then
43 matched=true
44 break
45 fi
46 done
47 if [[ "$matched" == false ]]; then
48 exit 1
49 fi
50 FLAGS+=("$arg")
51 # If flag expects a value and isn't using = syntax, skip next arg
52 if [[ "$arg" != *=* ]]; then
53 for vflag in "${FLAGS_WITH_VALUES[@]}"; do
54 if [[ "$flag" == "$vflag" ]]; then
55 skip_next=true
56 break
57 fi
58 done
59 fi
60 else
61 POSITIONAL+=("$arg")
62 fi
63done
64
65REPO="${GH_REPO:-${GITHUB_REPOSITORY:-}}"
66
67if [[ "$CMD" == "search issues" ]]; then
68 if [[ -z "$REPO" ]]; then
69 exit 1
70 fi
71 QUERY="${POSITIONAL[0]:-}"
72 QUERY_LOWER=$(echo "$QUERY" | tr '[:upper:]' '[:lower:]')
73 if [[ "$QUERY_LOWER" == *"repo:"* || "$QUERY_LOWER" == *"org:"* || "$QUERY_LOWER" == *"user:"* ]]; then
74 exit 1
75 fi
76 gh "$SUB1" "$SUB2" "$QUERY" --repo "$REPO" "${FLAGS[@]}"
77else
78 # Reject URLs in positional args to prevent cross-repo access
79 for pos in "${POSITIONAL[@]}"; do
80 if [[ "$pos" == http://* || "$pos" == https://* ]]; then
81 exit 1
82 fi
83 done
84 gh "$SUB1" "$SUB2" "${POSITIONAL[@]}" "${FLAGS[@]}"
85fi