Compare commits
1 Commits
step35/573
...
step35/429
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
666ff65ac6 |
@@ -46,6 +46,10 @@
|
||||
- role: cron_manager
|
||||
tags: [cron, schedule]
|
||||
|
||||
- role: emacs
|
||||
when: wizard_name == "Bezalel"
|
||||
tags: [emacs, daemon]
|
||||
|
||||
post_tasks:
|
||||
- name: "Final validation — scan for banned providers"
|
||||
shell: |
|
||||
|
||||
26
ansible/roles/emacs/README.md
Normal file
26
ansible/roles/emacs/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# emacs Ansible Role
|
||||
|
||||
Installs and configures a shared Emacs daemon for the Bezalel VPS.
|
||||
|
||||
## What it does
|
||||
|
||||
- Ensures `fleet` group exists
|
||||
- Installs Emacs (if needed)
|
||||
- Creates `/srv/fleet/emacs/sockets` (mode 2775, group fleet)
|
||||
- Creates `/srv/fleet/logs` (mode 2775)
|
||||
- Touches `/srv/fleet/logs/emacs-audit.log` (mode 0664)
|
||||
- Deploys `/root/.emacs.d/init.el` with:
|
||||
- Socket dir set to shared location
|
||||
- Group-accessible socket (#o660)
|
||||
- Audit hooks for file saves and client connections
|
||||
- Deploys `/usr/local/bin/emacsclient-bezalel` wrapper that logs caller identity
|
||||
- Deploys systemd unit `emacs-bezalel.service` and starts it
|
||||
|
||||
## Usage
|
||||
|
||||
The role is automatically included site-wide when `wizard_name == 'bezalel'`.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `emacsclient -s bezalel -e "(+ 1 1)"` should print `2` and return exit 0
|
||||
- `/srv/fleet/logs/emacs-audit.log` should contain user=... entries for each client and file write
|
||||
8
ansible/roles/emacs/handlers/main.yml
Normal file
8
ansible/roles/emacs/handlers/main.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
# Handlers for the emacs role
|
||||
|
||||
- name: Restart emacs-bezalel
|
||||
systemd:
|
||||
name: emacs-bezalel
|
||||
state: restarted
|
||||
daemon_reload: yes
|
||||
92
ansible/roles/emacs/tasks/main.yml
Normal file
92
ansible/roles/emacs/tasks/main.yml
Normal file
@@ -0,0 +1,92 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# emacs — Shared Emacs daemon with multi-user socket and audit trail
|
||||
# =============================================================================
|
||||
# Deploys and configures Emacs as a daemon on the VPS with:
|
||||
# - Named socket "bezalel" in /srv/fleet/emacs/sockets
|
||||
# - Group-writable socket for fleet access
|
||||
# - Audit logging for connections and file writes
|
||||
# - Per-user identity via EMACS_USER env
|
||||
# =============================================================================
|
||||
|
||||
- name: "Ensure fleet group exists (idempotent)"
|
||||
group:
|
||||
name: fleet
|
||||
state: present
|
||||
|
||||
- name: "Ensure Emacs package installed"
|
||||
package:
|
||||
name: emacs
|
||||
state: present
|
||||
when: machine_type == 'vps'
|
||||
ignore_errors: true # not critical if emacs already present
|
||||
|
||||
- name: "Create Emacs socket directory"
|
||||
file:
|
||||
path: /srv/fleet/emacs/sockets
|
||||
state: directory
|
||||
mode: '2775'
|
||||
group: fleet
|
||||
owner: root
|
||||
recurse: true
|
||||
|
||||
- name: "Create Emacs logs directory"
|
||||
file:
|
||||
path: /srv/fleet/logs
|
||||
state: directory
|
||||
mode: '2775'
|
||||
group: fleet
|
||||
owner: root
|
||||
recurse: true
|
||||
|
||||
- name: "Ensure audit log file exists with group write"
|
||||
file:
|
||||
path: /srv/fleet/logs/emacs-audit.log
|
||||
state: touch
|
||||
mode: '0664'
|
||||
group: fleet
|
||||
owner: root
|
||||
|
||||
- name: "Create root .emacs.d directory if missing"
|
||||
file:
|
||||
path: /root/.emacs.d
|
||||
state: directory
|
||||
mode: '0755'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: "Deploy Emacs init.el configuration"
|
||||
template:
|
||||
src: init.el.j2
|
||||
dest: /root/.emacs.d/init.el
|
||||
mode: '0644'
|
||||
owner: root
|
||||
group: root
|
||||
notify: Restart emacs-bezalel
|
||||
|
||||
- name: "Deploy emacsclient wrapper script"
|
||||
template:
|
||||
src: client-wrapper.sh.j2
|
||||
dest: /usr/local/bin/emacsclient-bezalel
|
||||
mode: '0755'
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: "Deploy systemd unit for Emacs daemon"
|
||||
template:
|
||||
src: emacs-bezalel.service.j2
|
||||
dest: /etc/systemd/system/emacs-bezalel.service
|
||||
mode: '0644'
|
||||
owner: root
|
||||
group: root
|
||||
notify: Restart emacs-bezalel
|
||||
|
||||
- name: "Reload systemd to pick up new unit"
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
|
||||
- name: "Ensure Emacs daemon is enabled and started"
|
||||
systemd:
|
||||
name: emacs-bezalel
|
||||
enabled: true
|
||||
state: started
|
||||
19
ansible/roles/emacs/templates/client-wrapper.sh.j2
Normal file
19
ansible/roles/emacs/templates/client-wrapper.sh.j2
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
# Emacs client wrapper for Bezalel — logs identity and delegates to emacsclient
|
||||
# This script must be installed setuid root? No — just group-executable.
|
||||
# AUDIT log: /srv/fleet/logs/emacs-audit.log
|
||||
|
||||
AUDIT_LOG="/srv/fleet/logs/emacs-audit.log"
|
||||
USERNAME="$(whoami)"
|
||||
TIMESTAMP="$(date -Iseconds)"
|
||||
|
||||
# Log the client connection attempt (pre-connect)
|
||||
echo "${TIMESTAMP} user=${USERNAME} action=emacsclient-connect args=$*" >> "${AUDIT_LOG}"
|
||||
|
||||
# Pass the username into the Emacs server environment so it can
|
||||
# appear in server-side audit entries as well.
|
||||
export EMACS_USER="${USERNAME}"
|
||||
|
||||
# Delegate to the real emacsclient, preserving all args.
|
||||
# The socket name 'bezalel' is configured by server-name in init.el.
|
||||
exec /usr/bin/emacsclient -s bezalel "$@"
|
||||
16
ansible/roles/emacs/templates/emacs-bezalel.service.j2
Normal file
16
ansible/roles/emacs/templates/emacs-bezalel.service.j2
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Emacs daemon for Bezalel (shared fleet service)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStart=/usr/bin/emacs --daemon=bezalel
|
||||
ExecStop=/usr/bin/emacsclient -s bezalel -e "(progn (setq kill-emacs-hook nil) (kill-emacs))"
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
# Ensure HOME is set correctly
|
||||
Environment=HOME=/root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
53
ansible/roles/emacs/templates/init.el.j2
Normal file
53
ansible/roles/emacs/templates/init.el.j2
Normal file
@@ -0,0 +1,53 @@
|
||||
;; Emacs init for Bezalel daemon — shared fleet service
|
||||
;; Managed by Ansible. DO NOT EDIT MANUALLY.
|
||||
;; Last updated: {{ ansible_date_time.iso8601 }}
|
||||
|
||||
;; -------------------- Socket configuration --------------------
|
||||
;; Use a shared, group-accessible socket directory
|
||||
(setq server-socket-dir "/srv/fleet/emacs/sockets/")
|
||||
|
||||
;; Ensure the socket directory exists with setgid so new files inherit group 'fleet'
|
||||
(let ((dir server-socket-dir))
|
||||
(unless (file-directory-p dir)
|
||||
(make-directory dir t))
|
||||
(set-file-modes dir #o2775))
|
||||
|
||||
;; Socket file permissions: group read/write so all fleet members can connect
|
||||
(setq server-socket-permissions #o660)
|
||||
|
||||
;; Name this daemon instance "bezalel" (matches systemd --daemon=bezalel)
|
||||
(setq server-name "bezalel")
|
||||
|
||||
;; -------------------- Audit trail --------------------
|
||||
(defvar emacs-audit-log "/srv/fleet/logs/emacs-audit.log"
|
||||
"Path to the fleet audit log for Emacs operations.")
|
||||
|
||||
(defun emacs-audit-log-entry (operation file &optional user)
|
||||
"Append an audit entry for OPERATION on FILE by USER.
|
||||
USER defaults to EMACS_USER env var (set by client wrapper) or
|
||||
the daemon's user-login-name."
|
||||
(let ((user (or user
|
||||
(getenv "EMACS_USER")
|
||||
(user-login-name))))
|
||||
(with-temp-buffer
|
||||
(insert (format "%s user=%s operation=%s file=%s\n"
|
||||
(format-time-string "%Y-%m-%dT%H:%M:%S%z")
|
||||
user
|
||||
operation
|
||||
(expand-file-name file)))
|
||||
(write-region (point-min) (point-max) emacs-audit-log 'append))))
|
||||
|
||||
;; Log every file buffer save
|
||||
(add-hook 'after-save-hook
|
||||
(lambda ()
|
||||
(when buffer-file-name
|
||||
(emacs-audit-log-entry "write" buffer-file-name))))
|
||||
|
||||
;; Also log client connections (best-effort via EMACS_USER)
|
||||
(add-hook 'server-after-make-frame-hook
|
||||
(lambda ()
|
||||
(let ((client (frame-parameter nil 'client)))
|
||||
(when client
|
||||
(emacs-audit-log-entry "connect" "emacsclient" (getenv "EMACS_USER"))))))
|
||||
|
||||
(provide 'init)
|
||||
Reference in New Issue
Block a user