libs/hooks/bin: add one-line module docstrings and # purpose: headers
every libs/*.py and hooks/*.py now starts with a one-line module docstring; every bin/* script starts with a `# purpose:` header. discovery-by-`ls`-and-read instead of by index. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
136313e9c3
commit
730625e36c
33 changed files with 60 additions and 0 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: upgrade RouterOS and routerboard firmware on `bundle:routeros` (or any selector) — usage: mikrotik-firmware-updater [<selector>...] [--yes].
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: print node.password and selected metadata-key passwords for one node — usage: passwords-for <node>.
|
||||||
|
|
||||||
from bundlewrap.repo import Repository
|
from bundlewrap.repo import Repository
|
||||||
from os.path import realpath, dirname
|
from os.path import realpath, dirname
|
||||||
|
|
|
||||||
1
bin/rcon
1
bin/rcon
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: send an RCON command to a left4dead2 server defined in node metadata — usage: rcon (list) | rcon <server> <command>.
|
||||||
|
|
||||||
from sys import argv
|
from sys import argv
|
||||||
from os.path import realpath, dirname
|
from os.path import realpath, dirname
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: starter template for new operator scripts under bin/.
|
||||||
|
|
||||||
from bundlewrap.repo import Repository
|
from bundlewrap.repo import Repository
|
||||||
from os.path import realpath, dirname
|
from os.path import realpath, dirname
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: upsert one 1Password login per `bundle:routeros` node, keyed on the bw node id.
|
||||||
|
|
||||||
from bundlewrap.repo import Repository
|
from bundlewrap.repo import Repository
|
||||||
from os.path import realpath, dirname
|
from os.path import realpath, dirname
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: add missing EXIF/QuickTime timestamps to photos in a directory using mdls + exiftool — usage: timestamp_icloud_photos_for_nextcloud -d <dir>.
|
||||||
|
|
||||||
from subprocess import check_output, CalledProcessError
|
from subprocess import check_output, CalledProcessError
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: apt-update and full-upgrade every non-dummy debian node, then reboot in WireGuard-aware order.
|
||||||
|
|
||||||
from bundlewrap.repo import Repository
|
from bundlewrap.repo import Repository
|
||||||
from os.path import realpath, dirname
|
from os.path import realpath, dirname
|
||||||
|
|
|
||||||
1
bin/wake
1
bin/wake
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: wake one node via WoL by name — usage: wake <node>.
|
||||||
|
|
||||||
from bundlewrap.repo import Repository
|
from bundlewrap.repo import Repository
|
||||||
from os.path import realpath, dirname
|
from os.path import realpath, dirname
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# purpose: print or QR-render a WireGuard client config from htz.mails metadata — usage: wireguard-client-config <client>.
|
||||||
|
|
||||||
from bundlewrap.repo import Repository
|
from bundlewrap.repo import Repository
|
||||||
from os.path import realpath, dirname
|
from os.path import realpath, dirname
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""known_hosts: pre-apply hook that writes all nodes' ssh/is_known_as entries to ~/.ssh/known_hosts_ckn."""
|
||||||
|
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""skip_local_nodes: skip apply on `localhost` nodes whose metadata `id` doesn't match this host's local_id."""
|
||||||
|
|
||||||
from bundlewrap.exceptions import SkipNode
|
from bundlewrap.exceptions import SkipNode
|
||||||
|
|
||||||
def node_apply_start(repo, node, interactive, **kwargs):
|
def node_apply_start(repo, node, interactive, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""test_ptr_records: bw-test gate verifying live A/PTR DNS records for the `mailserver` group via `dig @9.9.9.9`."""
|
||||||
|
|
||||||
from subprocess import check_output
|
from subprocess import check_output
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
"""unique_node_ids: bw-test + pre-apply gate ensuring metadata `id` is unique across all nodes."""
|
||||||
|
|
||||||
|
|
||||||
def test_unique_node_ids(repo):
|
def test_unique_node_ids(repo):
|
||||||
ids = {}
|
ids = {}
|
||||||
for node in repo.nodes:
|
for node in repo.nodes:
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
"""wake_on_lan: pre-apply / pre-run hook that wakes a node via libs.wol before bw connects to it."""
|
||||||
|
|
||||||
|
|
||||||
def wake_on_lan(node):
|
def wake_on_lan(node):
|
||||||
node.repo.libs.wol.wake(node)
|
node.repo.libs.wol.wake(node)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""apt: render sources.list.d entries and resolve apt-key file extensions, with codename/version templating."""
|
||||||
|
|
||||||
from re import match
|
from re import match
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from os.path import join, basename, exists
|
from os.path import join, basename, exists
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""bind: DNS view-routing helpers — match A/AAAA records against internal vs external views via repo-wide collation."""
|
||||||
|
|
||||||
from ipaddress import ip_address
|
from ipaddress import ip_address
|
||||||
|
|
||||||
def _values_from_all_nodes(type, name, zone):
|
def _values_from_all_nodes(type, name, zone):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
"""derive_string: deterministic byte-string derivation from a seed via ChaCha20 keystream."""
|
||||||
|
|
||||||
from hashlib import sha3_256
|
from hashlib import sha3_256
|
||||||
from itertools import count, islice
|
from itertools import count, islice
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""grafana: panel and Flux-query generators for Mako-templated dashboards under data/grafana/rows/."""
|
||||||
|
|
||||||
from mako.template import Template
|
from mako.template import Template
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""hashable: dict/set subclasses with stable __hash__ via canonical JSON — lets you nest dicts/sets inside sets in metadata."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""hmac: base64-encoded HMAC-SHA512 helper."""
|
||||||
|
|
||||||
import hmac, hashlib, base64
|
import hmac, hashlib, base64
|
||||||
|
|
||||||
def hmac_sha512(secret, iv):
|
def hmac_sha512(secret, iv):
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""ini: case-preserving ConfigParser parse/dumps for INI-style files where exact key casing must round-trip."""
|
||||||
|
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import json
|
import json
|
||||||
from bundlewrap.metadata import MetadataJSONEncoder
|
from bundlewrap.metadata import MetadataJSONEncoder
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""ip: A/AAAA-record derivation from a node's `network` metadata + cross-node IP collection."""
|
||||||
|
|
||||||
from ipaddress import ip_address, ip_interface
|
from ipaddress import ip_address, ip_interface
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""local: identifier of the bw host itself (read from ~/.config/bundlewrap/local_id) — paired with hooks/skip_local_nodes.py."""
|
||||||
|
|
||||||
from os.path import expanduser, exists
|
from os.path import expanduser, exists
|
||||||
from functools import cache
|
from functools import cache
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,5 @@
|
||||||
|
"""nextcloud: build `sudo -u www-data php occ ...` shell strings for use in actions."""
|
||||||
|
|
||||||
|
|
||||||
def occ(command, *args, **kwargs):
|
def occ(command, *args, **kwargs):
|
||||||
return f"""sudo -u www-data php /opt/nextcloud/occ {command} {' '.join(args)} {' '.join(f'--{name.replace("_", "-")}' + (f'={value}' if value else '') for name, value in kwargs.items())}"""
|
return f"""sudo -u www-data php /opt/nextcloud/occ {command} {' '.join(args)} {' '.join(f'--{name.replace("_", "-")}' + (f'={value}' if value else '') for name, value in kwargs.items())}"""
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
"""nginx: recursive nginx config-block rendering from a nested dict."""
|
||||||
|
|
||||||
|
|
||||||
def render_config(config):
|
def render_config(config):
|
||||||
return '\n'.join(render_lines(config))
|
return '\n'.join(render_lines(config))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""postgres: SCRAM-SHA-256 password-hash generation for postgres role provisioning."""
|
||||||
|
|
||||||
from base64 import standard_b64encode
|
from base64 import standard_b64encode
|
||||||
from hashlib import pbkdf2_hmac, sha256
|
from hashlib import pbkdf2_hmac, sha256
|
||||||
import hmac
|
import hmac
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""rsa: deterministic RSA private-key generation backed by a seeded PRNG."""
|
||||||
|
|
||||||
# https://stackoverflow.com/a/18266970
|
# https://stackoverflow.com/a/18266970
|
||||||
|
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""ssh: deterministic ed25519 keypair generation and salted known_hosts hashing."""
|
||||||
|
|
||||||
from base64 import b64decode, b64encode
|
from base64 import b64decode, b64encode
|
||||||
from hashlib import sha3_224, sha1
|
from hashlib import sha3_224, sha1
|
||||||
from functools import cache
|
from functools import cache
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""systemd: unit-file rendering (Mako) and a reusable hardening-options dict for sandboxed services."""
|
||||||
|
|
||||||
from mako.template import Template
|
from mako.template import Template
|
||||||
|
|
||||||
template = '''
|
template = '''
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""tools: identifier→IPs resolver (node|group|cidr), subnet-set deduplication, and bundle-requirement assertion."""
|
||||||
|
|
||||||
from ipaddress import ip_address, ip_network, IPv4Address, IPv4Network
|
from ipaddress import ip_address, ip_network, IPv4Address, IPv4Network
|
||||||
|
|
||||||
from bundlewrap.exceptions import NoSuchGroup, NoSuchNode, BundleError
|
from bundlewrap.exceptions import NoSuchGroup, NoSuchNode, BundleError
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""version: comparable Version class for dotted-int version strings."""
|
||||||
|
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""wireguard: deterministic WireGuard private/public key + PSK derivation, backed by repo.vault.random_bytes_as_base64_for."""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
from nacl.public import PrivateKey
|
from nacl.public import PrivateKey
|
||||||
from nacl.encoding import Base64Encoder
|
from nacl.encoding import Base64Encoder
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
"""wol: trigger a `wol-sleeper` waker node to run its configured wake command."""
|
||||||
|
|
||||||
from bundlewrap.utils.ui import io
|
from bundlewrap.utils.ui import io
|
||||||
from bundlewrap.utils.text import yellow, bold
|
from bundlewrap.utils.text import yellow, bold
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue