#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
# 
#    http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -euf -o pipefail

# This script must be installed in the .git/hooks directory.
# This is done automatically by the copyGitHooks/installGitHooks gradle tasks.
# It checks for any objects under the known private paths in any pushed refs.
# If it is present, we only allow pushing to the confluentinc/ce-kafka remote.
# See also: https://git-scm.com/docs/githooks#_pre_push

# The hook is called with two parameters which provide the name and location of the destination remote
REMOTE_NAME=$1
REMOTE_URL=$2

# If the remote repository is https://github.com/confluentinc/ce-kafka we can allow any
# push including with private paths as this is the intended internal/private repository
if [[ $REMOTE_URL =~ ^(https://|ssh://)?(git@)?github\.com[/:]confluentinc/ce-kafka(\.git)?/?$ ]]; then
    exit 0
fi

# Provide a helpful error message on pushes to personal forks of confluentinc/ce-kafka
if [[ $REMOTE_URL =~ ^(https://|ssh://)?(git@)?github\.com[/:][^/]*/ce-kafka(\.git)?/?$ ]]; then
    echo "FATAL: Pushing to private forks of https://github.com/confluentinc/* repositories is no longer permitted." >&2
    echo "See also: https://confluentinc.atlassian.net/wiki/spaces/TOOLS/pages/2879817082/GitHub+Private+Forks+Deprecation+FAQ" >&2
    exit 1
fi

# This is a partial list of known unique paths to https://github.com/confluentinc/ce-kafka
# If we find any objects under these paths in apache/kafka refs we will refuse the push
PRIVATE_PATHS=(
    "Confluent-README.md"
    "ce-audit/"
    "ce-auth-metadata/"
    "ce-auth-providers/"
    "ce-authorizer/"
    "ce-broker-plugins/"
    "ce-events/"
    "ce-events-api/"
    "ce-http-server/"
    "ce-kafka-client-plugins/"
    "ce-kafka-resources/"
    "ce-licensing/"
    "ce-metrics/"
    "ce-rbac/"
    "ce-resource-names/"
    "ce-rest-authorizer/"
    "ce-sbk/"
    "ce-security-extensions/"
    "ce-serializers/"
)

# Information about what is to be pushed is provided on the hook’s standard input with lines of the form:
# "<local ref> SP <local object name> SP <remote ref> SP <remote object name> LF"
PRIVATE_REFS=()
while read -r LOCAL_REF LOCAL_OID REMOTE_REF REMOTE_OID; do
    # If the local OID is zero we are deleting a remote ref, ignore
    if [[ "$LOCAL_OID" != "0000000000000000000000000000000000000000" ]]; then
        # If there are any commits that contain the private paths in that ref, add to PRIVATE_REFS array
        if [[ $(git rev-list --count "$LOCAL_OID" -- "${PRIVATE_PATHS[@]}") != "0" ]]; then
            PRIVATE_REFS[${#PRIVATE_REFS[@]}]="$LOCAL_REF ($LOCAL_OID) -> $REMOTE_REF ($REMOTE_OID)"
        fi
    fi
done

# If any private paths were found in the refs, prevent the push
if [[ ${#PRIVATE_REFS[@]} != 0 ]]; then
    # The remote is likely a known public repository like apache/kafka or confluentinc/kafka
    # Outright refuse to allow the push by exiting with an error and informing the user
    echo "FATAL: Refusing to allow push to remote '$REMOTE_NAME' ($REMOTE_URL)!" >&2
    echo "The following refs contain private source code from confluentinc/ce-kafka:" >&2
    printf "    %s\n" "${PRIVATE_REFS[@]}"
    exit 1
fi
