feat: add SSH login information and dotfiles status check to hello.py; include OpenSSH server tasks in Ansible configuration
Some checks failed
Nix Format Check / check-format (push) Failing after 39s

This commit is contained in:
Menno van Leeuwen 2025-03-10 19:05:18 +01:00
parent 6c095843ba
commit 7315809914
Signed by: vleeuwenmenno
SSH Key Fingerprint: SHA256:OJFmjANpakwD3F2Rsws4GLtbdz1TJ5tkQF0RZmF0TRE
6 changed files with 181 additions and 14 deletions

View File

@ -82,6 +82,9 @@ export NIXPKGS_ALLOW_UNFREE=1
# Allow insecure nixpkgs
export NIXPKGS_ALLOW_INSECURE=1
# 1Password SSH Agent
export SSH_AUTH_SOCK=$HOME/.1password/agent.sock
# Set DOTF_HOSTNAME to the hostname from .hostname file
# If this file doesn't exist, use mennos-unknown-hostname
export DOTF_HOSTNAME="mennos-unknown-hostname"

View File

@ -2,11 +2,129 @@
import os
import sys
import subprocess
from datetime import datetime
# Import helper functions
sys.path.append(os.path.join(os.path.expanduser("~/.dotfiles"), "bin"))
from helpers.functions import printfe, logo, _rainbow_color
def get_last_ssh_login():
"""Get information about the last SSH login"""
try:
# Using lastlog to get the last login information
result = subprocess.run(['lastlog2', '-u', os.environ.get("USER", "")],
capture_output=True, text=True)
if result.returncode == 0:
lines = result.stdout.strip().split('\n')
if len(lines) >= 2: # Header line + data line
# Parse the last login line for SSH connections
parts = lines[1].split()
if len(parts) >= 7 and 'ssh' in ' '.join(parts).lower():
time_str = ' '.join(parts[3:6])
ip = parts[-1]
return f"Last SSH login: {time_str} from {ip}"
return None
except Exception:
return None
def check_dotfiles_status():
"""Check if the dotfiles repository is dirty"""
dotfiles_path = os.environ.get("DOTFILES_PATH", os.path.expanduser("~/.dotfiles"))
try:
if not os.path.isdir(os.path.join(dotfiles_path, ".git")):
return None
# Check for git status details
status = {
'is_dirty': False,
'untracked': 0,
'modified': 0,
'staged': 0,
'commit_hash': '',
'unpushed': 0
}
# Get status of files
result = subprocess.run(['git', 'status', '--porcelain'],
cwd=dotfiles_path,
capture_output=True, text=True)
if result.stdout.strip():
status['is_dirty'] = True
for line in result.stdout.splitlines():
if line.startswith('??'):
status['untracked'] += 1
if line.startswith(' M') or line.startswith('MM'):
status['modified'] += 1
if line.startswith('M ') or line.startswith('A '):
status['staged'] += 1
# Get current commit hash
result = subprocess.run(['git', 'rev-parse', '--short', 'HEAD'],
cwd=dotfiles_path,
capture_output=True, text=True)
if result.returncode == 0:
status['commit_hash'] = result.stdout.strip()
# Count unpushed commits
# Fix: Remove capture_output and set stdout explicitly
result = subprocess.run(['git', 'log', '--oneline', '@{u}..'],
cwd=dotfiles_path,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True)
if result.returncode == 0:
status['unpushed'] = len(result.stdout.splitlines())
return status
except Exception as e:
print(f"Error checking dotfiles status: {str(e)}")
return None
def get_condensed_status():
"""Generate a condensed status line for trash and git status"""
status_parts = []
# Define ANSI color codes
RED = "\033[31m"
YELLOW = "\033[33m"
GREEN = "\033[32m"
BLUE = "\033[34m"
RESET = "\033[0m"
# Check trash status
trash_path = os.path.expanduser("~/.local/share/Trash/files")
try:
if os.path.exists(trash_path):
items = os.listdir(trash_path)
count = len(items)
if count > 0:
status_parts.append(f"[!] {count} file(s) in trash")
except Exception:
pass
# Check dotfiles status
dotfiles_status = check_dotfiles_status()
if dotfiles_status is not None:
if dotfiles_status['is_dirty']:
status_parts.append(f"{YELLOW}dotfiles is dirty{RESET}")
status_parts.append(f"{RED}[{dotfiles_status['untracked']}] untracked{RESET}")
status_parts.append(f"{YELLOW}[{dotfiles_status['modified']}] modified{RESET}")
status_parts.append(f"{GREEN}[{dotfiles_status['staged']}] staged{RESET}")
if dotfiles_status['commit_hash']:
status_parts.append(f"[{BLUE}{dotfiles_status['commit_hash']}{RESET}]")
if dotfiles_status['unpushed'] > 0:
status_parts.append(f"[!] You have {dotfiles_status['unpushed']} commit(s) to push")
else:
status_parts.append("Unable to check dotfiles status")
if status_parts:
return " - ".join(status_parts)
return None
def welcome():
"""Display welcome message with hostname and username"""
print()
@ -21,6 +139,16 @@ def welcome():
print(_rainbow_color(username), end="")
print("\033[36m]\033[0m")
# Display last SSH login info if available
ssh_login = get_last_ssh_login()
if ssh_login:
print(f"\033[33m{ssh_login}\033[0m")
# Display condensed status line
condensed_status = get_condensed_status()
if condensed_status:
print(f"\033[33m{condensed_status}\033[0m")
def main():
logo(continue_after=True)
welcome()

View File

@ -22,6 +22,10 @@
ansible.builtin.import_tasks: tasks/global/ollama.yml
become: true
- name: Include OpenSSH Server tasks
ansible.builtin.import_tasks: tasks/global/openssh-server.yml
become: true
- name: Ensure common packages are installed
ansible.builtin.package:
name:
@ -31,9 +35,11 @@
- trash-cli
- curl
- wget
# Python is used for the dotfiles CLI tools
- python3
- python3-pip
- python3-venv
- lastlog2 # Used for displaying last login information
state: present
become: true

View File

@ -0,0 +1,22 @@
---
- name: Ensure openssh-server is installed
ansible.builtin.package:
name: openssh-server
state: present
- name: Ensure SSH server configuration is proper
ansible.builtin.template:
src: templates/sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0644'
validate: '/usr/sbin/sshd -t -f %s'
notify: Restart SSH service
register: ssh_config
- name: Ensure SSH service is enabled and running
ansible.builtin.service:
name: ssh
state: started
enabled: true

View File

@ -1,4 +1,3 @@
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
@ -11,6 +10,15 @@
Include /etc/ssh/sshd_config.d/*.conf
# When systemd socket activation is used (the default), the socket
# configuration must be re-generated after changing Port, AddressFamily, or
# ListenAddress.
#
# For changes to take effect, run:
#
# systemctl daemon-reload
# systemctl restart ssh.socket
#
Port 400
#AddressFamily any
#ListenAddress 0.0.0.0
@ -25,12 +33,12 @@ Port 400
# Logging
#SyslogFacility AUTH
#LogLevel INFO
LogLevel INFO
# Authentication:
#LoginGraceTime 2m
PermitRootLogin prohibit-password
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
@ -54,8 +62,8 @@ PubkeyAuthentication yes
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication yes
PermitEmptyPasswords no
PasswordAuthentication no
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
@ -84,8 +92,8 @@ KbdInteractiveAuthentication no
# and KbdInteractiveAuthentication to 'no'.
UsePAM yes
AllowAgentForwarding yes
AllowTcpForwarding yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
@ -96,8 +104,8 @@ PrintMotd no
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
ClientAliveInterval 300
ClientAliveCountMax 2
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
@ -116,7 +124,7 @@ Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
X11Forwarding yes
AllowTcpForwarding yes
# PermitTTY no
# ForceCommand cvs server

View File

@ -39,11 +39,11 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1741379970,
"narHash": "sha256-Wh7esNh7G24qYleLvgOSY/7HlDUzWaL/n4qzlBePpiw=",
"lastModified": 1741513245,
"narHash": "sha256-7rTAMNTY1xoBwz0h7ZMtEcd8LELk9R5TzBPoHuhNSCk=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "36fd87baa9083f34f7f5027900b62ee6d09b1f2f",
"rev": "e3e32b642a31e6714ec1b712de8c91a3352ce7e1",
"type": "github"
},
"original": {