Commit ca28251
fix(launcher-standard): move PID/log to XDG dirs (security: symlink-attack hardening) (#175)
## Summary
The launcher-standard specified `/tmp/{app-name}-server.pid` and
`/tmp/{app-name}-server.log` as the required runtime paths. Predictable
names in a world-writable directory are a **symlink-attack target** on
any shared host:
- An attacker can pre-create `/tmp/<app>-server.pid` containing their
own PID. The launcher's `is_running()` returns true, and
`stop_server()` will `kill <attacker-pid>` — DoS or signal-handling
abuse.
- Similar pattern for the log: pre-symlink `/tmp/<app>-server.log` →
some target the attacker wants clobbered, then the launcher's
`nohup ... > LOG_FILE` does the write.
- The standard already warns "don't log sensitive information"
(§Best Practices > Security), but the predictable-path defence is
belt-and-braces.
## Fix
Route both to XDG dirs with documented fallback ladders:
- **PID** → `${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/<app>-server.pid`.
`$XDG_RUNTIME_DIR` is mode `0700` and user-scoped per the XDG Base
Directory spec (Linux). `$TMPDIR` covers macOS / BSDs (typically
`/var/folders/.../T`, per-user). `/tmp` remains only as a last-resort
fallback for hosts that set neither (rare).
- **Log** → `${XDG_STATE_HOME:-$HOME/.local/state}/<app>/server.log`.
Per-user, survives reboot, not world-writable. The `<app>` subdir
isolates each launcher's logs.
## Changes
Both files in the same commit per the lock-step requirement
(and the gate in #172):
- **`launcher/launcher-standard.a2ml`**
- `[runtime].pid-file-pattern` / `log-file-pattern` updated with
fallback ladders + commented rationale
- `[disinteg].preserve` updated to reference the new log dir
- **`docs/UX-standards/launcher-standard.adoc`**
- Standard Launcher Template snippet uses XDG paths + `mkdir -p`
for the state dir
- §What `--disinteg` removes / does not remove: paths updated
- Desktop File `Exec=` example log-arg updated
- Calling Convention daemon-chain example updated
- Debugging Checklist now uses `$LOG_FILE` / `$PID_FILE` variable
refs rather than literal paths
- §Best Practices > Logging: lead bullet rewritten with rationale
- §Best Practices > Security: new lead bullets explaining the
attack vector and the XDG choice
- §Compliance Checklist: "Log to predictable location (`/tmp/...`)"
replaced with the XDG requirement
Remaining `/tmp/` mentions in the prose are in *forbidden-patterns*
text that explicitly tells readers NOT to use `/tmp` — intentional.
## Compatibility
Bash-expansion syntax (`${VAR:-${VAR2:-/literal}}`) matches the
shell-expansion style already in the a2ml (e.g.
`$HOME/.local/share/applications` in `[integration.linux]`). Any
consumer that already interpolates `$HOME` here will handle
`${...:-...}`
without changes.
Existing launchers that hard-coded `/tmp/<app>-server.pid` continue to
work but become non-compliant; no break for them, just a green-field
contract change for new launchers and a flagged migration for old
ones.
## Coordination
- Independent of #170, #171, #172, #173. No file overlap.
- Lock-step gate (#172) will go green on first push (both files in
diff).
## Notes
- Spec `[spec].version` intentionally NOT bumped — five PRs (#170,
#171, #173, this one, plus any future) all touch the contract; the
merger sequences them.
## Test plan
- [x] a2ml parses (python tomllib): new patterns round-trip cleanly,
`[disinteg].preserve` reflects the new log path
- [x] No `/tmp/` literals remain in non-forbidden-patterns prose
(grep verified)
- [ ] Live lock-step gate (#172) goes green on first push
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent a12f765 commit ca28251
2 files changed
Lines changed: 33 additions & 15 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
| 23 | + | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
27 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
28 | 33 | | |
29 | 34 | | |
30 | 35 | | |
| |||
289 | 294 | | |
290 | 295 | | |
291 | 296 | | |
292 | | - | |
| 297 | + | |
293 | 298 | | |
294 | 299 | | |
295 | 300 | | |
296 | 301 | | |
297 | 302 | | |
298 | | - | |
| 303 | + | |
299 | 304 | | |
300 | 305 | | |
301 | 306 | | |
| |||
324 | 329 | | |
325 | 330 | | |
326 | 331 | | |
327 | | - | |
| 332 | + | |
328 | 333 | | |
329 | 334 | | |
330 | 335 | | |
| |||
398 | 403 | | |
399 | 404 | | |
400 | 405 | | |
401 | | - | |
| 406 | + | |
402 | 407 | | |
403 | 408 | | |
404 | 409 | | |
| |||
486 | 491 | | |
487 | 492 | | |
488 | 493 | | |
489 | | - | |
| 494 | + | |
490 | 495 | | |
491 | 496 | | |
492 | | - | |
| 497 | + | |
493 | 498 | | |
494 | 499 | | |
495 | 500 | | |
| |||
537 | 542 | | |
538 | 543 | | |
539 | 544 | | |
540 | | - | |
| 545 | + | |
541 | 546 | | |
542 | 547 | | |
543 | 548 | | |
| |||
548 | 553 | | |
549 | 554 | | |
550 | 555 | | |
551 | | - | |
| 556 | + | |
| 557 | + | |
552 | 558 | | |
553 | 559 | | |
554 | 560 | | |
| |||
567 | 573 | | |
568 | 574 | | |
569 | 575 | | |
570 | | - | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
571 | 579 | | |
572 | 580 | | |
573 | 581 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
75 | | - | |
76 | | - | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
77 | 87 | | |
78 | 88 | | |
79 | 89 | | |
| |||
134 | 144 | | |
135 | 145 | | |
136 | 146 | | |
137 | | - | |
| 147 | + | |
138 | 148 | | |
139 | 149 | | |
140 | 150 | | |
| |||
0 commit comments