diff --git a/go/cmd/compass/agent.go b/go/cmd/compass/agent.go index 5b5c5655..2da262ea 100644 --- a/go/cmd/compass/agent.go +++ b/go/cmd/compass/agent.go @@ -69,15 +69,17 @@ func runAgentStatus(ctx context.Context, client compassv1connect.CompassServiceC return renderAgentStatuses(out, statuses) } -// renderAgentStatuses prints a session-id + state column for each status. The -// state renders as the short operator-facing token (the enum name minus the -// AGENT_SESSION_STATE_ prefix, lowercased), so a WORKING session reads "working". +// renderAgentStatuses prints a session-id, state, runtime-tier, and egress-posture +// column for each status. Each enum renders as its short operator-facing token (the +// enum name minus its prefix, lowercased), so a WORKING host session with an armed +// posture reads "working host armed". func renderAgentStatuses(out io.Writer, statuses []*compassv1.AgentSessionStatus) error { - if _, err := fmt.Fprintf(out, "%-40s %s\n", "SESSION", "STATE"); err != nil { + if _, err := fmt.Fprintf(out, "%-40s %-14s %-16s %s\n", "SESSION", "STATE", "TIER", "EGRESS"); err != nil { return err } for _, s := range statuses { - if _, err := fmt.Fprintf(out, "%-40s %s\n", s.GetSessionId(), stateLabel(s.GetState())); err != nil { + if _, err := fmt.Fprintf(out, "%-40s %-14s %-16s %s\n", + s.GetSessionId(), stateLabel(s.GetState()), tierLabel(s.GetRuntimeTier()), egressLabel(s.GetEgressPosture())); err != nil { return err } } @@ -94,3 +96,39 @@ func stateLabel(state compassv1.AgentSessionState) string { } return strings.ToLower(strings.TrimPrefix(name, "AGENT_SESSION_STATE_")) } + +// tierLabel renders a RuntimeTier as the token the --backend flag accepts, so a +// tier a reader sees here is one they can select. That makes the mapping +// explicit rather than derived: stripping the enum prefix would print +// "apple_container", which the flag rejects. Unknown renders as unknown, never +// a tier a reader could mistake for containment. +func tierLabel(tier compassv1.RuntimeTier) string { + switch tier { + case compassv1.RuntimeTier_RUNTIME_TIER_PODMAN: + return "podman" + case compassv1.RuntimeTier_RUNTIME_TIER_MICROVM: + return "microvm" + case compassv1.RuntimeTier_RUNTIME_TIER_APPLE_CONTAINER: + return "apple-container" + case compassv1.RuntimeTier_RUNTIME_TIER_HOST: + return "host" + default: + return unspecifiedLabel + } +} + +// egressLabel renders an EgressPosture as the short operator-facing token: the +// enum name with the EGRESS_POSTURE_ prefix stripped and lowercased (ARMED → +// "armed", UNENFORCED → "unenforced"). The unspecified/unknown value renders as +// the shared unknown token — a user must never read an unknown posture as armed, +// which would show an uncontained session as contained. +func egressLabel(posture compassv1.EgressPosture) string { + if posture == compassv1.EgressPosture_EGRESS_POSTURE_UNSPECIFIED { + return unspecifiedLabel + } + name, ok := compassv1.EgressPosture_name[int32(posture)] + if !ok { + return unspecifiedLabel + } + return strings.ToLower(strings.TrimPrefix(name, "EGRESS_POSTURE_")) +} diff --git a/go/cmd/compass/agent_test.go b/go/cmd/compass/agent_test.go index c3601ff8..509dd153 100644 --- a/go/cmd/compass/agent_test.go +++ b/go/cmd/compass/agent_test.go @@ -115,3 +115,83 @@ func TestStateLabel(t *testing.T) { } } } + +// TestRenderAgentStatusesTierEgress asserts the tier and egress columns render +// the short operator-facing token a user reads. The zero-value case is +// load-bearing: an unset posture must read as unknown, never "armed", because a +// client that renders an unknown posture as armed would show an uncontained +// session as contained. +func TestRenderAgentStatusesTierEgress(t *testing.T) { + cases := []struct { + name string + status *compassv1.AgentSessionStatus + wantTier string + wantEg string + }{ + { + name: "host unenforced", + status: &compassv1.AgentSessionStatus{ + SessionId: "s-host", + State: compassv1.AgentSessionState_AGENT_SESSION_STATE_WORKING, + RuntimeTier: compassv1.RuntimeTier_RUNTIME_TIER_HOST, + EgressPosture: compassv1.EgressPosture_EGRESS_POSTURE_UNENFORCED, + }, + wantTier: "host", + wantEg: "unenforced", + }, + { + name: "podman armed", + status: &compassv1.AgentSessionStatus{ + SessionId: "s-podman", + State: compassv1.AgentSessionState_AGENT_SESSION_STATE_WORKING, + RuntimeTier: compassv1.RuntimeTier_RUNTIME_TIER_PODMAN, + EgressPosture: compassv1.EgressPosture_EGRESS_POSTURE_ARMED, + }, + wantTier: "podman", + wantEg: "armed", + }, + { + // The rendered tier must be a token --backend accepts; a derived + // label would print "apple_container", which the flag rejects. + name: "apple-container renders the hyphenated flag token", + status: &compassv1.AgentSessionStatus{ + SessionId: "s-apple", + State: compassv1.AgentSessionState_AGENT_SESSION_STATE_WORKING, + RuntimeTier: compassv1.RuntimeTier_RUNTIME_TIER_APPLE_CONTAINER, + EgressPosture: compassv1.EgressPosture_EGRESS_POSTURE_ARMED, + }, + wantTier: "apple-container", + wantEg: "armed", + }, + { + name: "zero value renders unknown", + status: &compassv1.AgentSessionStatus{ + SessionId: "s-zero", + State: compassv1.AgentSessionState_AGENT_SESSION_STATE_WORKING, + }, + wantTier: unspecifiedLabel, + wantEg: unspecifiedLabel, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + var out strings.Builder + if err := renderAgentStatuses(&out, []*compassv1.AgentSessionStatus{tc.status}); err != nil { + t.Fatalf("renderAgentStatuses: %v", err) + } + got := out.String() + for _, want := range []string{"TIER", "EGRESS", tc.status.GetSessionId(), tc.wantTier, tc.wantEg} { + if !strings.Contains(got, want) { + t.Errorf("rendered output %q missing %q", got, want) + } + } + if tc.name == "zero value renders unknown" { + for _, forbidden := range []string{"armed", "contained"} { + if strings.Contains(got, forbidden) { + t.Errorf("zero-value output %q must not contain %q", got, forbidden) + } + } + } + }) + } +}