Skip to content

docs(hardening): capture dedicated-server provisioning learnings - #212

Merged
robercano merged 1 commit into
mainfrom
docs/dedicated-server-provisioning-learnings
Aug 4, 2026
Merged

docs(hardening): capture dedicated-server provisioning learnings#212
robercano merged 1 commit into
mainfrom
docs/dedicated-server-provisioning-learnings

Conversation

@robercano

Copy link
Copy Markdown
Owner

Findings from a real bare-metal Ubuntu 26.04 provisioning run, so the next box (and the next repo's agent user) does not re-derive them.

docs/HARDENING.md

  • New 4a: on Ubuntu >=24.04, bwrap-userns-restrict stacks bwrap's children into unpriv_bwrap ("audit deny capability"), so Claude Code's nested seccomp layer cannot get CAP_SYS_ADMIN and every Bash call fails with "apply-seccomp: write /proc/self/setgroups". Records the diagnostics that distinguish this from a kernel-wide userns block, the three remedies with their costs, and that dropping sandbox.network alone does not help.
  • Step 4 (systemd): document the user-unit-safe directive set. The full block implies CapabilityBoundingSet changes needing CAP_SETPCAP, which a systemd --user manager lacks -> 218/CAPABILITIES crash loop that is-active still reports as active.
  • Step 4 (managed settings): drop disableBypassPermissionsMode and warn that it disables the bypass mode the loop runs in, rather than pinning it.
  • Step 1: remove the 23 redundant Write() deny twins; only Edit() rules are matched, and an Edit rule already covers every file-editing tool.
  • Step 2: PAT belongs in gh auth, not .env (set -a would shadow the bot identity); Actions stays No access; bot token is repo-only, never workflow; verify with .permissions -> push:true; note that one shared bot account is a cross-repo credential per-repo Unix users do not contain.
  • Step 5: ufw coexistence, policy accept + trailing drop, DNS-refresh rot, root-run drop notifier.
  • Step 7 + checklist: run /orchestrator:harden inside the agent's clone (settings.local.json is gitignored and does not travel), one agent user per repo, and checklist items that cannot pass by inspection.

.claude/commands/provision.md

  • Field notes: paste hygiene (long lines/heredocs arrive mangled), never accept a sub-agent's security diagnosis without reproducing it, a permission-denied from the admin account is not evidence of absence, and is-active is not evidence a unit is healthy.
  • Per-agent-user progress files; box-global vs per-repo phases.
  • Threaded updates through phases 1, 3, 4, 5, 6 and 7.

.claude/settings.json

  • Remove the two inert WSL-era Write(//mnt/) and Write(//etc/) rules that emitted a startup warning on every session.

Sub-task

<title — the single scoped unit this branch delivers>

Module / boundary

  • Module: <path>
  • Confirm: all changed files are within this boundary ✅ / ❌ (explain)

What changed

Gates

gate status
build
lint
typecheck
tests
coverage (vs threshold)
security

Reviewer verdicts

  • correctness:
  • tests:
  • security:
  • performance:

Open risks / follow-ups

🤖 Generated via the multi-agent orchestrator template.

Findings from a real bare-metal Ubuntu 26.04 provisioning run, so the next
box (and the next repo's agent user) does not re-derive them.

docs/HARDENING.md
- New 4a: on Ubuntu >=24.04, bwrap-userns-restrict stacks bwrap's children
  into unpriv_bwrap ("audit deny capability"), so Claude Code's nested
  seccomp layer cannot get CAP_SYS_ADMIN and every Bash call fails with
  "apply-seccomp: write /proc/self/setgroups". Records the diagnostics that
  distinguish this from a kernel-wide userns block, the three remedies with
  their costs, and that dropping sandbox.network alone does not help.
- Step 4 (systemd): document the user-unit-safe directive set. The full
  block implies CapabilityBoundingSet changes needing CAP_SETPCAP, which a
  systemd --user manager lacks -> 218/CAPABILITIES crash loop that
  `is-active` still reports as active.
- Step 4 (managed settings): drop disableBypassPermissionsMode and warn
  that it disables the bypass mode the loop runs in, rather than pinning it.
- Step 1: remove the 23 redundant Write() deny twins; only Edit() rules are
  matched, and an Edit rule already covers every file-editing tool.
- Step 2: PAT belongs in `gh auth`, not .env (set -a would shadow the bot
  identity); Actions stays No access; bot token is repo-only, never
  workflow; verify with `.permissions` -> push:true; note that one shared
  bot account is a cross-repo credential per-repo Unix users do not contain.
- Step 5: ufw coexistence, policy accept + trailing drop, DNS-refresh rot,
  root-run drop notifier.
- Step 7 + checklist: run /orchestrator:harden inside the agent's clone
  (settings.local.json is gitignored and does not travel), one agent user
  per repo, and checklist items that cannot pass by inspection.

.claude/commands/provision.md
- Field notes: paste hygiene (long lines/heredocs arrive mangled), never
  accept a sub-agent's security diagnosis without reproducing it, a
  permission-denied from the admin account is not evidence of absence, and
  `is-active` is not evidence a unit is healthy.
- Per-agent-user progress files; box-global vs per-repo phases.
- Threaded updates through phases 1, 3, 4, 5, 6 and 7.

.claude/settings.json
- Remove the two inert WSL-era Write(//mnt/**) and Write(//etc/**) rules
  that emitted a startup warning on every session.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robercano robercano self-assigned this Aug 4, 2026
@robercano
robercano merged commit 998cdc1 into main Aug 4, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant