Add Authentik Git login helper
This commit is contained in:
16
README.md
16
README.md
@@ -53,6 +53,7 @@ TARGET_DIR=~/work/rta-handbook \
|
|||||||
## Daily Flow
|
## Daily Flow
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
section0-docs auth login
|
||||||
section0-docs doctor
|
section0-docs doctor
|
||||||
section0-docs pull
|
section0-docs pull
|
||||||
|
|
||||||
@@ -69,16 +70,20 @@ the lab operator side; collaborators do not need the home-lab repo.
|
|||||||
|
|
||||||
## Contributor Setup
|
## Contributor Setup
|
||||||
|
|
||||||
Anonymous clone/read works on the private lab network. Pushing requires an
|
Anonymous clone/read works on the private lab network. Pushing requires
|
||||||
account or access token with write access to `section0/rta-handbook`.
|
Authentik login through the helper.
|
||||||
|
|
||||||
Run this once per checkout:
|
Run this once per checkout:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
section0-docs configure
|
section0-docs auth login
|
||||||
```
|
```
|
||||||
|
|
||||||
Then prove write access without changing `main`:
|
The login opens Authentik in your browser, configures the Git author from your
|
||||||
|
identity, and installs the repo Git credential. After that, normal Git tooling
|
||||||
|
works too.
|
||||||
|
|
||||||
|
Prove write access without changing `main`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
section0-docs push-test
|
section0-docs push-test
|
||||||
@@ -87,7 +92,8 @@ section0-docs push-test
|
|||||||
`push-test` does not commit files and does not change `main`. It pushes the
|
`push-test` does not commit files and does not change `main`. It pushes the
|
||||||
current commit to a temporary scratch branch, then deletes that branch
|
current commit to a temporary scratch branch, then deletes that branch
|
||||||
immediately. If Git prompts for a password, use a Gitea access token rather
|
immediately. If Git prompts for a password, use a Gitea access token rather
|
||||||
than your normal account password.
|
than your normal account password. If login is healthy, Git should usually get
|
||||||
|
the credential from your local credential store.
|
||||||
|
|
||||||
## End-To-End Smoke Test
|
## End-To-End Smoke Test
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ TARGET_DIR="${TARGET_DIR:-$HOME/Developer/Section0/rta-handbook}"
|
|||||||
COMMAND_DIR="${COMMAND_DIR:-$HOME/.local/bin}"
|
COMMAND_DIR="${COMMAND_DIR:-$HOME/.local/bin}"
|
||||||
COMMAND_NAME="${COMMAND_NAME:-section0-docs}"
|
COMMAND_NAME="${COMMAND_NAME:-section0-docs}"
|
||||||
COMMAND_PATH="$COMMAND_DIR/$COMMAND_NAME"
|
COMMAND_PATH="$COMMAND_DIR/$COMMAND_NAME"
|
||||||
|
SERVER_URL="${SECTION0_SERVER_URL:-https://ops.virgil.info/md-to-section0-api}"
|
||||||
|
|
||||||
step() {
|
step() {
|
||||||
printf "\n==> %s\n" "$*"
|
printf "\n==> %s\n" "$*"
|
||||||
@@ -37,12 +38,17 @@ cat > "$COMMAND_PATH" <<EOF
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
REPO_DIR="$TARGET_DIR"
|
REPO_DIR="$TARGET_DIR"
|
||||||
|
SERVER_URL="$SERVER_URL"
|
||||||
|
SESSION_DIR="\${SECTION0_SESSION_DIR:-\$HOME/.config/section0-docs}"
|
||||||
|
SESSION_PATH="\$SESSION_DIR/session.json"
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<USAGE
|
cat <<USAGE
|
||||||
section0-docs - helper for Section 0 shared Markdown docs
|
section0-docs - helper for Section 0 shared Markdown docs
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
|
auth login open Authentik and install Git credentials
|
||||||
|
auth status show current saved login
|
||||||
configure set Git author name/email for this repo
|
configure set Git author name/email for this repo
|
||||||
doctor check clone, author, remote, and read access
|
doctor check clone, author, remote, and read access
|
||||||
open print the repo path
|
open print the repo path
|
||||||
@@ -54,6 +60,8 @@ Commands:
|
|||||||
help show this help
|
help show this help
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
section0-docs auth login
|
||||||
|
section0-docs auth status
|
||||||
section0-docs doctor
|
section0-docs doctor
|
||||||
section0-docs configure
|
section0-docs configure
|
||||||
section0-docs pull
|
section0-docs pull
|
||||||
@@ -67,7 +75,135 @@ AFFiNE copies are refreshed from Git.
|
|||||||
USAGE
|
USAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
need_python() {
|
||||||
|
command -v python3 >/dev/null 2>&1 || {
|
||||||
|
echo "python3 is required for Authentik login JSON handling" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json_get() {
|
||||||
|
need_python
|
||||||
|
python3 -c 'import json,sys; data=json.load(sys.stdin); cur=data
|
||||||
|
for part in sys.argv[1].split("."):
|
||||||
|
cur = cur.get(part, "") if isinstance(cur, dict) else ""
|
||||||
|
print(cur if cur is not None else "")' "\$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
open_url() {
|
||||||
|
if command -v open >/dev/null 2>&1; then
|
||||||
|
open "\$1" >/dev/null 2>&1 || true
|
||||||
|
elif command -v xdg-open >/dev/null 2>&1; then
|
||||||
|
xdg-open "\$1" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
credential_host() {
|
||||||
|
need_python
|
||||||
|
python3 -c 'from urllib.parse import urlparse; import sys
|
||||||
|
url=urlparse(sys.argv[1])
|
||||||
|
print(url.netloc)' "\$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_git_credential() {
|
||||||
|
remote="\$1"
|
||||||
|
username="\$2"
|
||||||
|
password="\$3"
|
||||||
|
host="\$(credential_host "\$remote")"
|
||||||
|
protocol="\$(printf "%s" "\$remote" | sed -n "s#^\\([^:/]*\\)://.*#\\1#p")"
|
||||||
|
[ -n "\$protocol" ] || protocol="http"
|
||||||
|
if [ "\$(uname -s 2>/dev/null || true)" = "Darwin" ]; then
|
||||||
|
git -C "\$REPO_DIR" config credential.helper osxkeychain
|
||||||
|
fi
|
||||||
|
printf "protocol=%s\nhost=%s\nusername=%s\npassword=%s\n\n" "\$protocol" "\$host" "\$username" "\$password" \
|
||||||
|
| git -C "\$REPO_DIR" credential approve
|
||||||
|
}
|
||||||
|
|
||||||
|
auth_login() {
|
||||||
|
need_python
|
||||||
|
mkdir -p "\$SESSION_DIR"
|
||||||
|
device_json="\$(curl -fsS -X POST "\$SERVER_URL/device")"
|
||||||
|
code="\$(printf "%s" "\$device_json" | json_get code)"
|
||||||
|
auth_url="\$(printf "%s" "\$device_json" | json_get authUrl)"
|
||||||
|
[ -n "\$code" ] && [ -n "\$auth_url" ] || {
|
||||||
|
echo "login server did not return a device code" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "Opening Authentik login:"
|
||||||
|
echo " \$auth_url"
|
||||||
|
open_url "\$auth_url"
|
||||||
|
echo "Waiting for login..."
|
||||||
|
token_json=""
|
||||||
|
i=0
|
||||||
|
while [ "\$i" -lt 90 ]; do
|
||||||
|
token_json="\$(curl -fsS "\$SERVER_URL/device/\$code/token" 2>/dev/null || true)"
|
||||||
|
access_token="\$(printf "%s" "\${token_json:-{}}" | json_get accessToken 2>/dev/null || true)"
|
||||||
|
[ -n "\$access_token" ] && break
|
||||||
|
i=\$((i + 1))
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
[ -n "\${access_token:-}" ] || {
|
||||||
|
echo "timed out waiting for Authentik login" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
access_json="\$(curl -fsS -X POST -H "Authorization: Bearer \$access_token" "\$SERVER_URL/section0/git/access")"
|
||||||
|
ok="\$(printf "%s" "\$access_json" | json_get ok)"
|
||||||
|
[ "\$ok" = "True" ] || [ "\$ok" = "true" ] || {
|
||||||
|
echo "Git access broker did not return credentials:" >&2
|
||||||
|
printf "%s\n" "\$access_json" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
remote="\$(printf "%s" "\$access_json" | json_get remote)"
|
||||||
|
git_username="\$(printf "%s" "\$access_json" | json_get git.username)"
|
||||||
|
git_password="\$(printf "%s" "\$access_json" | json_get git.password)"
|
||||||
|
author_name="\$(printf "%s" "\$access_json" | json_get author.name)"
|
||||||
|
author_email="\$(printf "%s" "\$access_json" | json_get author.email)"
|
||||||
|
[ -n "\$remote" ] && [ -n "\$git_username" ] && [ -n "\$git_password" ] || {
|
||||||
|
echo "Git access broker response was incomplete" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
git -C "\$REPO_DIR" remote set-url origin "\$remote"
|
||||||
|
git -C "\$REPO_DIR" config user.name "\$author_name"
|
||||||
|
git -C "\$REPO_DIR" config user.email "\$author_email"
|
||||||
|
install_git_credential "\$remote" "\$git_username" "\$git_password"
|
||||||
|
python3 -c 'import json,sys
|
||||||
|
token=json.loads(sys.argv[1])
|
||||||
|
access=json.loads(sys.argv[2])
|
||||||
|
print(json.dumps({
|
||||||
|
"authenticated": True,
|
||||||
|
"serverUrl": sys.argv[3],
|
||||||
|
"authentik": token.get("authentik", {}),
|
||||||
|
"author": access.get("author", {}),
|
||||||
|
"remote": access.get("remote", ""),
|
||||||
|
"credentialUser": access.get("git", {}).get("username", "")
|
||||||
|
}, indent=2))' "\$token_json" "\$access_json" "\$SERVER_URL" > "\$SESSION_PATH"
|
||||||
|
chmod 600 "\$SESSION_PATH"
|
||||||
|
echo "Authenticated: \$author_email"
|
||||||
|
echo "Git remote: \$remote"
|
||||||
|
echo "Git user: \$git_username"
|
||||||
|
echo "Session: \$SESSION_PATH"
|
||||||
|
}
|
||||||
|
|
||||||
case "\${1:-help}" in
|
case "\${1:-help}" in
|
||||||
|
auth)
|
||||||
|
case "\${2:-}" in
|
||||||
|
login)
|
||||||
|
auth_login
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
if [ -f "\$SESSION_PATH" ]; then
|
||||||
|
cat "\$SESSION_PATH"
|
||||||
|
else
|
||||||
|
echo "not authenticated; run: section0-docs auth login" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "usage: section0-docs auth <login|status>" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
configure)
|
configure)
|
||||||
current_name="\$(git -C "\$REPO_DIR" config user.name || true)"
|
current_name="\$(git -C "\$REPO_DIR" config user.name || true)"
|
||||||
current_email="\$(git -C "\$REPO_DIR" config user.email || true)"
|
current_email="\$(git -C "\$REPO_DIR" config user.email || true)"
|
||||||
@@ -146,6 +282,7 @@ Remote: $REPO_URL
|
|||||||
Helper: $COMMAND_PATH
|
Helper: $COMMAND_PATH
|
||||||
|
|
||||||
Daily flow:
|
Daily flow:
|
||||||
|
$COMMAND_NAME auth login
|
||||||
$COMMAND_NAME doctor
|
$COMMAND_NAME doctor
|
||||||
$COMMAND_NAME pull
|
$COMMAND_NAME pull
|
||||||
# edit Markdown
|
# edit Markdown
|
||||||
|
|||||||
Reference in New Issue
Block a user