Last active
February 10, 2025 20:32
-
-
Save ocap-kirk/803bdfb4592d6c60a12cc9d6121d5455 to your computer and use it in GitHub Desktop.
Permit.io Configure GitOps with Github
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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