Skip to content

Overhaul policy/session/TUI + fix 15 review findings - #3

Merged
Kritoooo merged 2 commits into
mainfrom
policy-session-tui-overhaul
Jun 29, 2026
Merged

Kritoooo merged 2 commits into
mainfrom
policy-session-tui-overhaul

Conversation

@Kritoooo

Copy link
Copy Markdown
Member

Overview

This branch overhauls the policy model, sessions, skills, and policy TUI (commit a1b92f3), then fixes 15 findings from a code review of that overhaul (commit b7de37c). All fixes carry regression tests; go build ./... and go test ./... pass.

Correctness fixes

# Fix
1 Audit repair data loss — TruncateBroken now cuts by a new VerifyResult.BrokenIndex (slice position) instead of the stored seq value, so a tampered/displaced seq can no longer delete all valid records or report a false-success repair.
2 Silent policy migration — loading a config with removed v0.5.1 keys (defaults, top-level/per-override policy/allow_rules) now fails fast with a migration hint rather than silently dropping them and flipping allow-by-default to deny-all.
3 Session-per-host — group/multi-target runs derive a unique session id per host (<base>@<host>), restoring one-session-per-host; stale comments corrected.
4 Action-less rule — empty action defaults to allow again (invalid non-empty actions still error), so one malformed rule no longer bricks all run execution.
5 Orphaned overrides — RemoveHostRule/RemoveHostGroup work on a host override whose host left inventory.
6 inventory rm ordering — policy is cleared/validated/saved before the inventory removal is written, so a policy failure can't leave an orphaned override.
7 host_overrides ordering — custom MarshalYAML preserves file order, protecting equal-priority tie-breaks across a save round-trip.
8 Named rule edit — editing a named global rule in the TUI preserves its Name, so CLI policy rule update/rm <name> still resolves it.
9 / 10 Non-deterministic ordering — session.Summaries and TUI buildGroups sort same-second rows deterministically by id.

Cleanup

Idempotent group stamping · shared internal/fileutil.WriteFileAtomic (policy + inventory saves) · saveValidatedPolicy helper replacing ~12 repeated validate+save pairs · removed dead parseHostRuleInput · simplified withHost target reset.

⚠️ Behavioral notes for reviewers

  • Finding 2 is a breaking change: an old-format policy.yaml now errors on load (with a migration hint) instead of silently degrading. This is intentional — under default-deny semantics, silent migration would lock users out.
  • Finding 3 changes the session_id format to embed the host (<base>@<host>), which is visible in audit records and session ls.

Testing

  • go build ./... — clean
  • go test ./... — all packages pass; new regression tests cover findings 1, 3, 4, 5, 6, 7, 8, 9, 10.

🤖 Generated with Claude Code

Kritoooo and others added 2 commits June 28, 2026 20:30
A sequence of related changes to the policy engine, session handling,
the operator skill, and the policy TUI. They were developed together and
the per-file edits interleave across themes, so they land as one commit.

Sessions
- `run` now requires an explicit session (--session or AGENTSSH_SESSION);
  with neither it errors (exit 2, ErrNoSession). Removed the 30-min
  idle-window resume and the on-disk session pointer file, so logically
  distinct tasks can no longer merge by time. Added `agentssh session new`.

Skills
- Replaced the two task playbooks (restart-service, investigate-cpu) with
  a single `agentssh-usage` operating manual: trust boundary, one-session-
  per-task discipline, policy, bounded output, audit — best practices for
  using AgentSSH, not a server runbook.

Policy engine
- Rebuilt as a two-tier, priority-ordered, default-deny model. Evaluate:
  host tier (host:<name> + matched group overrides, pooled, priority desc,
  ties by file order) then global tier, else a hard-coded default-deny.
  Rules carry allow/deny + priority; action is required. Seed policy.yaml
  is a default-deny scaffold with no active rules.

Rule groups + policy TUI
- Added rule_groups: reusable authoring presets the engine never evaluates.
  Stamping copies a group's rules onto a host with a `group` provenance tag
  (snapshot, not a live link); removing a group filters host rules by that
  tag. Engine ignores rule_groups and Rule.Group.
- Entry-level Policy tab: card grid (Global card + one per rule group) with
  drill-in rule CRUD. Host detail Policy pane is a borderless unified list
  (host + global in one list, SCOPE/PRIORITY/ACTION/COMMAND/GROUP columns,
  host tier first then priority desc, global rows read-only).

Help bar
- Slimmed every footer to a few essential keys; the ? overlay carries the
  full, grouped key list (FullHelp is now preserved, not flattened).

Host rules ownership
- Deleting a host cascades to remove its own host:<name> rules; group
  overrides and rule groups are left intact.
- Renamed the "binding" terminology to "host rules": HostBinding ->
  HostRuleSet, HostBindingGroup -> HostRulesKey, LookupHostBinding ->
  LookupHostRules, SetHostBinding -> SetHostRules, RemoveHostBinding ->
  ClearHostRules, ErrHostUnbound -> ErrNoHostRules (HostOverride /
  host_overrides unchanged).

Review fixes (from an adversarial pass)
- removeSelectedHostGroup now removes the group from the selected row's own
  source override, not blindly from the host's binding (wrong-rule delete).
- RemoveHostGroup rejects an empty group name (would have matched every
  ungrouped rule via Group == "").

go build ./... && go vet ./... && go test ./... all green; default-deny,
host>global, snapshot provenance, and the host-delete cascade were
exercised end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses correctness bugs and cleanups found reviewing the policy/session/
TUI overhaul. All fixes carry regression tests; go build/test pass.

Correctness:
- audit: TruncateBroken now cuts by break index (new VerifyResult.BrokenIndex),
  not the stored seq value, so a tampered seq can no longer wipe valid records
  or report a false-success repair.
- policy: reject removed v0.5.1 schema keys (defaults / policy / allow_rules)
  on load with a migration hint instead of silently dropping them and flipping
  allow-by-default to deny-all.
- run: group/multi-target runs derive a unique session id per host, restoring
  one-session-per-host; stale comments corrected.
- policy: empty action defaults to allow again (invalid actions still error),
  so one action-less rule no longer bricks all execution.
- policy/store: RemoveHostRule/RemoveHostGroup work on orphaned host overrides
  whose host left inventory.
- inventory rm: clear/validate/save policy before writing inventory removal,
  avoiding an orphaned override on policy failure.
- policy: custom MarshalYAML preserves host_overrides file order, protecting
  equal-priority tie-breaks across a save round-trip.
- tui: editing a named global rule preserves its Name so CLI lookups still work.
- session/tui: deterministic secondary sort by id for same-second sessions
  and session groups.

Cleanup:
- idempotent group stamping; shared internal/fileutil.WriteFileAtomic for
  policy+inventory saves; saveValidatedPolicy helper; remove dead
  parseHostRuleInput; simplify withHost target reset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Kritoooo
Kritoooo merged commit ed7c98d into main Jun 29, 2026
2 checks passed
@Kritoooo
Kritoooo deleted the policy-session-tui-overhaul branch August 31, 2026 05:52
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