style: reword em-dashes; put colons inside bold run-in labels
Punctuation sweep across README, ROADMAP, and the script's comments: em-dashes become colons, commas, or parentheses; bold list labels take the colon inside the bold with lowercase text after. Comments only in the script, no code changes.
This commit is contained in:
parent
ff92d812ad
commit
be3fb049d2
3 changed files with 30 additions and 30 deletions
|
|
@ -92,7 +92,7 @@ The mechanism is identical everywhere: group ownership and mode bits plus `tmux
|
||||||
|
|
||||||
`party` assumes you already know and trust everyone you add to the group; it is not a public access-control system. Both gates above protect each party, and the **auth gate** (`tmux server-access`) is authoritative, with the filesystem gate as defense in depth.
|
`party` assumes you already know and trust everyone you add to the group; it is not a public access-control system. Both gates above protect each party, and the **auth gate** (`tmux server-access`) is authoritative, with the filesystem gate as defense in depth.
|
||||||
|
|
||||||
The threat model is **accidents, not adversaries**. `party` runs where everyone already shares the box, so the ownership and symlink gates in front of destructive operations (`close`'s directory removal, moderation) are there so a stale roster, a typo, or two racing `party host` invocations can't remove or hijack the wrong thing — that the same checks would also stop a malicious group member is a side effect, not the design goal. New checks should earn their place by preventing a plausible *mistake*, not by closing a hypothetical attack from a friend.
|
The threat model is **accidents, not adversaries**. `party` runs where everyone already shares the box, so the ownership and symlink gates in front of destructive operations (`close`'s directory removal, moderation) are there so a stale roster, a typo, or two racing `party host` invocations can't remove or hijack the wrong thing: that the same checks would also stop a malicious group member is a side effect, not the design goal. New checks should earn their place by preventing a plausible *mistake*, not by closing a hypothetical attack from a friend.
|
||||||
|
|
||||||
Three honest caveats, with the full detail in `man party`:
|
Three honest caveats, with the full detail in `man party`:
|
||||||
|
|
||||||
|
|
|
||||||
30
ROADMAP.md
30
ROADMAP.md
|
|
@ -3,49 +3,49 @@
|
||||||
Direction, not promises. Two rules govern everything below (README
|
Direction, not promises. Two rules govern everything below (README
|
||||||
§Security has the long form):
|
§Security has the long form):
|
||||||
|
|
||||||
- **Accidents, not adversaries.** New checks earn their place by
|
- **Accidents, not adversaries:** new checks earn their place by
|
||||||
preventing a plausible mistake — stale state, a typo, a race — not by
|
preventing a plausible mistake (stale state, a typo, a race), not by
|
||||||
closing a hypothetical attack from a friend.
|
closing a hypothetical attack from a friend.
|
||||||
- **Social, not mechanical.** New features earn their place by
|
- **Social, not mechanical:** new features earn their place by
|
||||||
encouraging people to work together in a terminal, not by adding
|
encouraging people to work together in a terminal, not by adding
|
||||||
machinery.
|
machinery.
|
||||||
|
|
||||||
## Next — small, high value
|
## Next: small, high value
|
||||||
|
|
||||||
- **`party knock <name>`** — an uninvited group member pings the host
|
- **`party knock <name>`:** an uninvited group member pings the host
|
||||||
via `write(1)`: "veg wants to join fiesta". `party list` already
|
via `write(1)`: "veg wants to join fiesta". `party list` already
|
||||||
shows invite-only parties; knock completes that loop. The feature
|
shows invite-only parties; knock completes that loop. The feature
|
||||||
most likely to cause spontaneous pairing.
|
most likely to cause spontaneous pairing.
|
||||||
- **`party log`** — per-party transcript via `tmux pipe-pane` into the
|
- **`party log`:** per-party transcript via `tmux pipe-pane` into the
|
||||||
per-party dir (group-readable so every attendee can grab a copy);
|
per-party dir (group-readable so every attendee can grab a copy);
|
||||||
`party log --stop` ends it. "What did we do last night?" for
|
`party log --stop` ends it. "What did we do last night?" for
|
||||||
collectives, and the audit trail human+AI co-work needs.
|
collectives, and the audit trail human+AI co-work needs.
|
||||||
- **`party clean`** — remove the caller's own crash leftovers (dirs
|
- **`party clean`:** remove the caller's own crash leftovers (dirs
|
||||||
they own whose socket is dead), turning the manual `rm -rf` recovery
|
they own whose socket is dead), turning the manual `rm -rf` recovery
|
||||||
in host's error message into a verb.
|
in host's error message into a verb.
|
||||||
|
|
||||||
## Later
|
## Later
|
||||||
|
|
||||||
- **Group ergonomics** — the default `party` group needs root and a
|
- **Group ergonomics:** the default `party` group needs root and a
|
||||||
relog before anyone's first party. On boxes where everyone already
|
relog before anyone's first party. On boxes where everyone already
|
||||||
shares a group, `host` could offer (or default to) the caller's
|
shares a group, `host` could offer (or default to) the caller's
|
||||||
primary group when `party` doesn't exist. Fits the trust model;
|
primary group when `party` doesn't exist. Fits the trust model;
|
||||||
costs a little existence-confidentiality.
|
costs a little existence-confidentiality.
|
||||||
- **One liveness primitive** — fold `is_party_alive` into
|
- **One liveness primitive:** fold `is_party_alive` into
|
||||||
`party_conn_state`; two concepts where one would do.
|
`party_conn_state`; two concepts where one would do.
|
||||||
- **Matrix** — live validation on NetBSD and DragonFly; one
|
- **Matrix:** live validation on NetBSD and DragonFly; one
|
||||||
interactive attach/role/switch pass per release (automated coverage
|
interactive attach/role/switch pass per release (automated coverage
|
||||||
is all non-interactive).
|
is all non-interactive).
|
||||||
|
|
||||||
## Resist — by design, not by neglect
|
## Resist: by design, not by neglect
|
||||||
|
|
||||||
- **No network transport.** Same-host is the perimeter; beyond it lies
|
- **No network transport:** same-host is the perimeter; beyond it lies
|
||||||
reinventing ssh.
|
reinventing ssh.
|
||||||
- **No per-pane ACLs.** tmux can't enforce them; faking it with hooks
|
- **No per-pane ACLs:** tmux can't enforce them; faking it with hooks
|
||||||
would be a leaky abstraction. Document the limitation instead.
|
would be a leaky abstraction. Document the limitation instead.
|
||||||
- **No config files, no plugin system, no ACL syscalls.** One POSIX
|
- **No config files, no plugin system, no ACL syscalls:** one POSIX
|
||||||
file that runs on a 30-year spread of UNIXes is the identity; the
|
file that runs on a 30-year spread of UNIXes is the identity; the
|
||||||
2026-04 simplification that removed per-OS ACL dispatch is not to be
|
2026-04 simplification that removed per-OS ACL dispatch is not to be
|
||||||
unwound.
|
unwound.
|
||||||
- **Watch the file size.** Heavy why-comments are a feature; feature
|
- **Watch the file size:** heavy why-comments are a feature; feature
|
||||||
growth that pushes the single file far past its current size is not.
|
growth that pushes the single file far past its current size is not.
|
||||||
|
|
|
||||||
28
party
28
party
|
|
@ -118,7 +118,7 @@ user_in_party_group() {
|
||||||
|
|
||||||
# Soft assertion: caller is in TMUX_PARTY_GROUP. Fails loudly with
|
# Soft assertion: caller is in TMUX_PARTY_GROUP. Fails loudly with
|
||||||
# remediation instructions when not. Called by cmd_host before any
|
# remediation instructions when not. Called by cmd_host before any
|
||||||
# filesystem work; the other subcommands don't need it — non-members
|
# filesystem work; the other subcommands don't need it: non-members
|
||||||
# are stopped by the FS perimeter itself (EACCES at the per-party dir)
|
# are stopped by the FS perimeter itself (EACCES at the per-party dir)
|
||||||
# and get the friendlier group-gate message in cmd_join.
|
# and get the friendlier group-gate message in cmd_join.
|
||||||
require_caller_in_group() {
|
require_caller_in_group() {
|
||||||
|
|
@ -245,7 +245,7 @@ roster_read() {
|
||||||
[ -n "$RR_PARTY_NAME" ] || return 1
|
[ -n "$RR_PARTY_NAME" ] || return 1
|
||||||
|
|
||||||
# Pattern parity with cmd_host. The basename glob (party-*:*.d) is
|
# Pattern parity with cmd_host. The basename glob (party-*:*.d) is
|
||||||
# permissive — names like 'a b' or 'my.party' match the glob but
|
# permissive: names like 'a b' or 'my.party' match the glob but
|
||||||
# validate_party_name rejects them (dots are banned: tmux rewrites
|
# validate_party_name rejects them (dots are banned: tmux rewrites
|
||||||
# them in session names). Run the canonical validator so the
|
# them in session names). Run the canonical validator so the
|
||||||
# invariant cmd_host enforces on write is also checked on read.
|
# invariant cmd_host enforces on write is also checked on read.
|
||||||
|
|
@ -342,12 +342,12 @@ is_party_alive() {
|
||||||
|
|
||||||
# Classify the caller's relationship to a party socket. Prints exactly
|
# Classify the caller's relationship to a party socket. Prints exactly
|
||||||
# one of:
|
# one of:
|
||||||
# ok — live tmux server, the caller is authorized.
|
# ok : live tmux server, the caller is authorized.
|
||||||
# unauthorized — live tmux server, but it refused us. CAUTION, the
|
# unauthorized : live tmux server, but it refused us. CAUTION, the
|
||||||
# reason this function exists: tmux answers a
|
# reason this function exists: tmux answers a
|
||||||
# non-allowlisted user with "access not allowed" on
|
# non-allowlisted user with "access not allowed" on
|
||||||
# stderr and EXIT STATUS 0 (verified live on 3.3a,
|
# stderr and EXIT STATUS 0 (verified live on 3.3a,
|
||||||
# 3.5a, and 3.6/SunOS), for every command — including
|
# 3.5a, and 3.6/SunOS), for every command, including
|
||||||
# has-session, which then reports any target as
|
# has-session, which then reports any target as
|
||||||
# existing. Exit codes alone cannot distinguish
|
# existing. Exit codes alone cannot distinguish
|
||||||
# authorized from unauthorized. We deliberately do NOT
|
# authorized from unauthorized. We deliberately do NOT
|
||||||
|
|
@ -357,8 +357,8 @@ is_party_alive() {
|
||||||
# list-clients writes nothing to stderr, so rc 0 plus
|
# list-clients writes nothing to stderr, so rc 0 plus
|
||||||
# ANY stderr output classifies as unauthorized. Should
|
# ANY stderr output classifies as unauthorized. Should
|
||||||
# tmux ever warn on an authorized call, that degrades
|
# tmux ever warn on an authorized call, that degrades
|
||||||
# to a hidden party — never to a false "ok".
|
# to a hidden party, never to a false "ok".
|
||||||
# dead — nothing speaking the tmux protocol at that socket
|
# dead : nothing speaking the tmux protocol at that socket
|
||||||
# (stale roster, killed server, AF_UNIX impostor).
|
# (stale roster, killed server, AF_UNIX impostor).
|
||||||
party_conn_state() {
|
party_conn_state() {
|
||||||
_cs_err=$("$PARTY_TMUX" -S "$1" list-clients 2>&1 >/dev/null) \
|
_cs_err=$("$PARTY_TMUX" -S "$1" list-clients 2>&1 >/dev/null) \
|
||||||
|
|
@ -480,8 +480,8 @@ compute_default_party_name() {
|
||||||
# Absolute path to this script, for embedding in tmux server state that
|
# Absolute path to this script, for embedding in tmux server state that
|
||||||
# outlives this invocation (the status-right #() widget runs with the
|
# outlives this invocation (the status-right #() widget runs with the
|
||||||
# tmux server's PATH, which need not contain an installed `party`).
|
# tmux server's PATH, which need not contain an installed `party`).
|
||||||
# $0 forms: absolute — take it; relative-with-slash — anchor to cwd;
|
# $0 forms: absolute, take it; relative-with-slash, anchor to cwd;
|
||||||
# bare word — resolve via PATH, falling back to $0 verbatim. No `--`
|
# bare word, resolve via PATH, falling back to $0 verbatim. No `--`
|
||||||
# after command -v/dirname/basename: old illumos userland predates it,
|
# after command -v/dirname/basename: old illumos userland predates it,
|
||||||
# and $0 here never starts with '-'.
|
# and $0 here never starts with '-'.
|
||||||
party_self_path() {
|
party_self_path() {
|
||||||
|
|
@ -510,11 +510,11 @@ tmux_party_setup_server() {
|
||||||
# hosts at most one socket so a fixed name is safe.
|
# hosts at most one socket so a fixed name is safe.
|
||||||
notify_script="${sock%/*}/.party-notify"
|
notify_script="${sock%/*}/.party-notify"
|
||||||
# Two heredocs: the first (expanding) pins the tmux binary the party
|
# Two heredocs: the first (expanding) pins the tmux binary the party
|
||||||
# was hosted with — a bare `tmux` from the server's PATH may be a
|
# was hosted with: a bare `tmux` from the server's PATH may be a
|
||||||
# different, older binary than $PARTY_TMUX, which is the whole reason
|
# different, older binary than $PARTY_TMUX, which is the whole reason
|
||||||
# PARTY_TMUX exists. The second (quoted) is the static body. A
|
# PARTY_TMUX exists. The second (quoted) is the static body. A
|
||||||
# PARTY_TMUX containing a double quote, $, or backslash would break
|
# PARTY_TMUX containing a double quote, $, or backslash would break
|
||||||
# the pin; that's accepted — it's the host's own env var on their
|
# the pin; that's accepted: it's the host's own env var on their
|
||||||
# own party.
|
# own party.
|
||||||
cat > "$notify_script" <<EOF
|
cat > "$notify_script" <<EOF
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
@ -540,7 +540,7 @@ EOF
|
||||||
"$PARTY_TMUX" -S "$sock" set-option -s exit-empty on
|
"$PARTY_TMUX" -S "$sock" set-option -s exit-empty on
|
||||||
party_self=$(party_self_path)
|
party_self=$(party_self_path)
|
||||||
# The #() body is run by the tmux server via sh, so the embedded
|
# The #() body is run by the tmux server via sh, so the embedded
|
||||||
# paths are single-quoted — a path containing a single quote, a `)`,
|
# paths are single-quoted: a path containing a single quote, a `)`,
|
||||||
# or `#{` (tmux's #() parser ends at the first unescaped `)`) is
|
# or `#{` (tmux's #() parser ends at the first unescaped `)`) is
|
||||||
# accepted breakage (host's own install path).
|
# accepted breakage (host's own install path).
|
||||||
"$PARTY_TMUX" -S "$sock" set-option -g status-right \
|
"$PARTY_TMUX" -S "$sock" set-option -g status-right \
|
||||||
|
|
@ -975,7 +975,7 @@ EOF
|
||||||
# by the host via `party invite`). Pre-flight here so the user gets
|
# by the host via `party invite`). Pre-flight here so the user gets
|
||||||
# a helpful message instead of an opaque tmux refusal. For an
|
# a helpful message instead of an opaque tmux refusal. For an
|
||||||
# unauthorized caller server-access -l prints its refusal on stderr
|
# unauthorized caller server-access -l prints its refusal on stderr
|
||||||
# with EMPTY stdout (and exit 0 — see party_conn_state), so the awk
|
# with EMPTY stdout (and exit 0, see party_conn_state), so the awk
|
||||||
# match comes up empty and we land in the exit-13 branch.
|
# match comes up empty and we land in the exit-13 branch.
|
||||||
acl_line=$("$PARTY_TMUX" -S "$RR_SOCKET" server-access -l 2>/dev/null \
|
acl_line=$("$PARTY_TMUX" -S "$RR_SOCKET" server-access -l 2>/dev/null \
|
||||||
| awk -v u="$USER" '$1 == u { print; exit }')
|
| awk -v u="$USER" '$1 == u { print; exit }')
|
||||||
|
|
@ -1242,7 +1242,7 @@ cmd_list() {
|
||||||
"$RR_HOST_USER" "$RR_PARTY_NAME" "$attendees" "$group_tag"
|
"$RR_HOST_USER" "$RR_PARTY_NAME" "$attendees" "$group_tag"
|
||||||
else
|
else
|
||||||
# Live server, connection refused: we can't count attendees
|
# Live server, connection refused: we can't count attendees
|
||||||
# (list-clients is behind the auth gate — its empty stdout
|
# (list-clients is behind the auth gate: its empty stdout
|
||||||
# used to render here as a bogus "0 attendee(s)"), but the
|
# used to render here as a bogus "0 attendee(s)"), but the
|
||||||
# party is real and the caller can ask for an invite.
|
# party is real and the caller can ask for an invite.
|
||||||
printf '%-12s %-30s invite-only (ask %s)%s\n' \
|
printf '%-12s %-30s invite-only (ask %s)%s\n' \
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue