Skip to content

Instantly share code, notes, and snippets.

@ocap-kirk
Last active February 10, 2025 20:32
Show Gist options
  • Select an option

  • Save ocap-kirk/803bdfb4592d6c60a12cc9d6121d5455 to your computer and use it in GitHub Desktop.

Select an option

Save ocap-kirk/803bdfb4592d6c60a12cc9d6121d5455 to your computer and use it in GitHub Desktop.
Permit.io Configure GitOps with Github
#!/bin/bash
# Parse command line arguments
DEBUG=false
API_KEY=""
GIT_REPO=""
BRANCH_NAME="main"
KEY_FILE=""
GENERATE_KEY=false
PROJECT_KEY=""
# Function to log debug messages
debug_log() {
if $DEBUG && [ -n "$1" ]; then # Only output if there's content
echo -e "\n🔍 DEBUG: $1"
fi
}
# Function to prompt for required variables
get_input() {
local prompt=$1
local var_name=$2
local is_secret=${3:-false}
if [ "$is_secret" = true ]; then
debug_log "Requesting secret input for: $var_name"
read -sp "$prompt: " value
echo
debug_log "Input received for: $var_name (Value: $value)"
else
debug_log "Requesting input for: $var_name"
read -p "$prompt: " value
debug_log "Input received for: $var_name (Value: $value)"
fi
eval $var_name=\$value
}
# Function to prompt for yes/no with default yes
get_confirmation() {
local prompt=$1
debug_log "Requesting confirmation: $prompt"
read -p "$prompt [Y/n]: " response
response=${response:-"y"}
case "$response" in
[yY]|[yY][eE][sS])
debug_log "Confirmation response: Yes"
return 0 ;;
*)
debug_log "Confirmation response: No"
return 1 ;;
esac
}
# Function to make API calls and handle responses
make_api_call() {
local method=$1
local url=$2
local auth_header=$3
local data=$4
debug_log "Making API call:"
debug_log "Method: $method"
debug_log "URL: $url"
local curl_opts="-s"
local debug_file
local response_file
debug_file=$(mktemp)
response_file=$(mktemp)
# Make the actual API call
if [ -n "$data" ]; then
if $DEBUG; then
curl -v -X "$method" "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $auth_header" \
--data-binary "$data" 2>"$debug_file" 1>"$response_file"
else
curl $curl_opts -X "$method" "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $auth_header" \
--data-binary "$data" > "$response_file"
fi
else
if $DEBUG; then
curl -v -X "$method" "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $auth_header" 2>"$debug_file" 1>"$response_file"
else
curl $curl_opts -X "$method" "$url" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $auth_header" > "$response_file"
fi
fi
# Show debug output if in debug mode
if $DEBUG; then
debug_log "Curl debug output:"
cat "$debug_file" >&2
fi
# Get the raw response without any cleanup
local response
response=$(cat "$response_file")
# Clean up temp files
rm -f "$debug_file" "$response_file"
debug_log "API response: $response"
echo "$response"
}
# Function to format private key
format_private_key() {
local keyfile=$1
if [ ! -f "$keyfile" ]; then
debug_log "Error: SSH key file not found"
echo "Error: SSH key file not found at $keyfile"
exit 1
fi
# Format key first
local formatted_key=$(awk -v ORS='\\n' '1' "$keyfile")
# Debug after formatting is complete
debug_log "Formatting private key from file: $keyfile"
debug_log "Private key formatted (first line): $(echo "$formatted_key" | head -n1)..."
echo "$formatted_key"
}
# Function to check repository status
check_repo_status() {
local project_key=$1
local repo_key=$2
local api_key=$3
local max_attempts=12
local attempt=1
debug_log "Starting repository status check"
debug_log "Project key: $project_key"
debug_log "Repo key: $repo_key"
while [ $attempt -le $max_attempts ]; do
debug_log "Status check attempt $attempt of $max_attempts"
# Make the API call directly with curl
local response
response=$(curl -s -X GET "https://api.permit.io/v2/projects/$project_key/repos" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $api_key")
debug_log "Raw response: $response"
# Extract status using jq
local status
status=$(echo "$response" | jq -r --arg key "$repo_key" '.[] | select(.key == $key) | .status')
debug_log "Parsed status: '$status'"
case "$status" in
"valid")
echo -e "\nRepository status is now valid! ✅"
return 0
;;
"invalid")
debug_log "Invalid status detected"
echo "Repository validation failed. Status is: invalid"
return 1
;;
"")
if [ $attempt -eq $max_attempts ]; then
debug_log "Max attempts reached, no status found"
echo "Repository not found after $max_attempts attempts"
return 1
fi
echo "Waiting for repository... (attempt $attempt of $max_attempts)"
sleep 5
;;
*)
if [ $attempt -eq $max_attempts ]; then
debug_log "Max attempts reached with status: $status"
echo "Repository status is still: $status after $max_attempts attempts"
return 1
fi
echo "Current status: $status. Waiting 5 seconds before next check..."
sleep 5
;;
esac
attempt=$((attempt + 1))
done
}
# Function to generate SSH key
generate_ssh_key() {
local key_path=$1
local email="help@permit.io"
debug_log "Generating SSH key at: $key_path"
debug_log "Email: $email"
if [ -f "$key_path" ]; then
debug_log "Existing key found at $key_path: $(cat "$key_path")"
if get_confirmation "SSH key already exists at $key_path. Generate a new one?"; then
debug_log "Removing existing key"
rm -f "$key_path" "$key_path.pub"
else
return 0
fi
fi
debug_log "Creating .ssh directory if needed"
mkdir -p "$(dirname "$key_path")"
echo "Generating new SSH key..."
debug_log "Running ssh-keygen"
ssh-keygen -t ecdsa -b 521 -C "$email" -f "$key_path" -N ""
if [ $? -eq 0 ]; then
debug_log "SSH key generated successfully"
debug_log "Private key: $(cat "$key_path")"
debug_log "Public key: $(cat "$key_path.pub")"
echo "✅ SSH key generated successfully"
echo -e "\nPublic key (you'll need to add this to GitHub):"
cat "$key_path.pub"
echo -e "\nTo add this key to GitHub as a deploy key, follow these steps:"
echo "1. Go to your GitHub repository's settings"
echo "2. Follow the instructions at: https://docs.permit.io/integrations/gitops/github#add-ssh-deploy-key"
echo "3. Make sure to enable 'Allow write access' when adding the deploy key"
echo -e "\nIMPORTANT: The deploy key must have write access for Permit.io to work properly."
if get_confirmation "Have you added the public key to GitHub as a deploy key with write access?"; then
return 0
else
debug_log "User hasn't added key to GitHub yet"
echo "Please add the public key to GitHub and run the script again."
exit 1
fi
else
debug_log "Error generating SSH key"
echo "Error generating SSH key"
exit 1
fi
}
# Function to create an arrow-key selection menu
select_option() {
# Initialize variables
local cursor=0
local options=("$@")
local selected=false
local key=""
# Hide cursor
tput civis
# Function to print menu
print_menu() {
local idx=0
echo -e "\nSelect a project:"
for opt in "${options[@]}"; do
if [ $idx -eq $cursor ]; then
echo -e " ➜ \033[1m$opt\033[0m" # Bold text for selected item
else
echo -e " $opt"
fi
((idx++))
done
}
# Clear previous output and print menu
clear_menu() {
printf "\033[%dA" $((${#options[@]} + 2)) # Move cursor up
printf "\033[J" # Clear from cursor to end of screen
}
# Show first menu
print_menu
# Handle key input
while ! $selected; do
# Read a single key press
read -rsn1 key
case $key in
"A") # Up arrow
if [ $cursor -gt 0 ]; then
((cursor--))
clear_menu
print_menu
fi
;;
"B") # Down arrow
if [ $cursor -lt $((${#options[@]} - 1)) ]; then
((cursor++))
clear_menu
print_menu
fi
;;
"") # Enter key
selected=true
echo # New line after selection
;;
esac
done
# Show cursor again
tput cnorm
# Return the selected index
return $cursor
}
usage() {
echo "Usage: $0 [options]"
echo "Options:"
echo " --debug Enable debug mode"
echo " --api-key KEY Permit.io API key"
echo " --git-repo URL Git repository URL"
echo " --branch NAME Branch name (default: main)"
echo " --key-path PATH Path to SSH key"
echo " --generate-key Generate new SSH key"
echo " --project-key KEY Project key"
echo " -h, --help Show this help message"
exit 1
}
# Parse command line arguments
while [[ "$#" -gt 0 ]]; do
case $1 in
--debug) DEBUG=true ;;
--api-key) API_KEY="$2"; shift ;;
--git-repo) GIT_REPO="$2"; shift ;;
--branch) BRANCH_NAME="$2"; shift ;;
--key-path) KEY_FILE="$2"; shift ;;
--generate-key) GENERATE_KEY=true ;;
--project-key) PROJECT_KEY="$2"; shift ;;
-h|--help) usage ;;
*) echo "Unknown parameter: $1"; usage ;;
esac
shift
done
# Validate required parameters
if [ -z "$API_KEY" ]; then
get_input "Enter your API Key" API_KEY true
fi
if [ -z "$GIT_REPO" ]; then
get_input "Enter Git repository URL" GIT_REPO
fi
if [ -z "$KEY_FILE" ]; then
if [ "$GENERATE_KEY" = true ]; then
DEFAULT_KEY_PATH="$HOME/.ssh/permit_io_key"
get_input "Enter path for new SSH key (default: $DEFAULT_KEY_PATH)" KEY_FILE
KEY_FILE=${KEY_FILE:-$DEFAULT_KEY_PATH}
else
get_input "Enter path to existing SSH private key" KEY_FILE
fi
fi
# Modify the SSH key handling section
if [ "$GENERATE_KEY" = true ]; then
debug_log "Using key path: $KEY_FILE"
generate_ssh_key "$KEY_FILE"
else
# Verify the key exists
if [ ! -f "$KEY_FILE" ]; then
debug_log "Specified key file not found: $KEY_FILE"
echo "Error: SSH key file not found at $KEY_FILE"
exit 1
fi
debug_log "Using existing SSH key at: $KEY_FILE"
debug_log "Key content: $(cat "$KEY_FILE")"
echo "Using existing SSH key at $KEY_FILE"
fi
# Generate random key for the repository
REPO_KEY=$(openssl rand -hex 32)
debug_log "Generated repository key: $REPO_KEY"
# First API call to get projects
echo "Fetching projects..."
projects_response=$(curl -s -X GET 'https://api.permit.io/v2/projects' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_KEY")
debug_log "Raw projects response: $projects_response"
# Parse projects into arrays for menu selection
project_keys=()
project_names=()
# Parse each project using the working jq command
while read -r key name; do
debug_log "Found project - Key: $key, Name: $name"
if [ -n "$key" ]; then
project_keys+=("$key")
project_names+=("$name")
fi
done < <(echo "$projects_response" | jq -r '.[] | "\(.key) \(.name)"')
project_count=${#project_keys[@]}
debug_log "Found $project_count projects"
if [ $project_count -eq 0 ]; then
echo "No projects found. Please create a project first."
exit 1
fi
# If there's only one project, use it automatically
if [ $project_count -eq 1 ]; then
PROJECT_KEY="${project_keys[0]}"
debug_log "Auto-selected single project key: $PROJECT_KEY"
echo "Using project: ${project_names[0]} [$PROJECT_KEY]"
else
# Display available projects
echo -e "\nAvailable projects:"
for i in "${!project_keys[@]}"; do
echo "[$((i+1))] ${project_names[$i]} (${project_keys[$i]})"
done
# Get user selection
while true; do
get_input "Enter the number of the project to use" selection
if [[ "$selection" =~ ^[0-9]+$ ]] && [ "$selection" -ge 1 ] && [ "$selection" -le "${#project_keys[@]}" ]; then
PROJECT_KEY="${project_keys[$((selection-1))]}"
debug_log "Selected project key: $PROJECT_KEY"
echo "Selected project: ${project_names[$((selection-1))]} [$PROJECT_KEY]"
break
else
echo "Invalid selection. Please enter a number between 1 and ${#project_keys[@]}"
fi
done
fi
# Check for existing repositories
echo "Creating new repository..."
# Format key first, without any debug messages
PRIVATE_KEY=$(awk -v ORS='\\n' '1' "$KEY_FILE")
# Create clean JSON
repo_json=$(cat <<EOF
{
"url": "$GIT_REPO",
"main_branch_name": "$BRANCH_NAME",
"credentials": {
"auth_type": "ssh",
"username": "git",
"private_key": "$PRIVATE_KEY"
},
"key": "$REPO_KEY"
}
EOF
)
# Validate JSON before proceeding
if ! echo "$repo_json" | jq '.' >/dev/null 2>&1; then
debug_log "Invalid JSON payload:"
echo "$repo_json" | jq '.'
exit 1
fi
# Now show debug info
debug_log "Repository creation payload:"
echo "$repo_json" | jq '.'
# Show curl command
debug_log "Curl command to execute:"
echo "curl -X POST 'https://api.permit.io/v2/projects/$PROJECT_KEY/repos' \\"
echo " -H 'Content-Type: application/json' \\"
echo " -H 'Authorization: Bearer $API_KEY' \\"
echo " --data-binary '$(echo "$repo_json" | jq -c '.')'"
# Create repository
debug_log "Making repository creation API call to:"
debug_log "POST https://api.permit.io/v2/projects/$PROJECT_KEY/repos"
# Show the curl command that will be executed
curl_cmd="curl -X POST 'https://api.permit.io/v2/projects/$PROJECT_KEY/repos' \\
-H 'Content-Type: application/json' \\
-H 'Authorization: Bearer $API_KEY' \\
--data-binary '$repo_json'"
debug_log "Curl command to execute:"
echo "$curl_cmd"
if $DEBUG; then
get_confirmation "Does this curl command look correct?" || exit 1
fi
repo_response=$(make_api_call "POST" "https://api.permit.io/v2/projects/$PROJECT_KEY/repos" "$API_KEY" "$repo_json")
echo "Repository creation response:"
echo "$repo_response" | jq '.'
# Function to activate repository
activate_repository() {
local project_key=$1
local repo_key=$2
local api_key=$3
debug_log "Activating repository"
debug_log "Project key: $project_key"
debug_log "Repo key: $repo_key"
# Make the activation call directly with curl
local response
response=$(curl -s -X PUT "https://api.permit.io/v2/projects/$project_key/repos/$repo_key/activate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $api_key")
debug_log "Raw activation response: $response"
# Check if activation was successful by looking for active_policy_repo_id
if echo "$response" | jq -e '.active_policy_repo_id' >/dev/null 2>&1; then
local project_name
local project_id
local active_repo_id
project_name=$(echo "$response" | jq -r '.name')
project_id=$(echo "$response" | jq -r '.id')
active_repo_id=$(echo "$response" | jq -r '.active_policy_repo_id')
debug_log "Activation successful"
echo -e "\n✅ Repository activated successfully!"
echo "Project '$project_name' is now using this repository as its active policy source."
echo -e "\nDetails:"
echo "Repository Key: $repo_key"
echo "Project ID: $project_id"
echo "Active Policy Repo ID: $active_repo_id"
return 0
else
debug_log "Activation failed - Response: $response"
echo "❌ Repository activation failed."
echo "Please verify activation status manually."
return 1
fi
}
# Check repository status before activation
if check_repo_status "$PROJECT_KEY" "$REPO_KEY" "$API_KEY"; then
if get_confirmation "Would you like to activate the repository now?"; then
debug_log "Proceeding with repository activation"
echo "Activating repository..."
if ! activate_repository "$PROJECT_KEY" "$REPO_KEY" "$API_KEY"; then
debug_log "Repository activation failed"
echo "Cannot activate repository. Please check the configuration and try again."
exit 1
fi
else
debug_log "User chose not to activate repository"
echo "Repository created but not activated. You can activate it later using the API."
fi
else
debug_log "Repository status check failed"
echo "Cannot activate repository due to invalid status."
echo "Please check the repository configuration and try again."
exit 1
fi
debug_log "Script completed successfully"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment