From 7a6f4c792b2d1d678642a64307a2788ac5b355f8 Mon Sep 17 00:00:00 2001 From: Ali Hesari Date: Sun, 20 Sep 2026 03:18:25 +0200 Subject: [PATCH] feat: add the activity and audit commands fopost activity list reads GET /v1/activity; fopost activity audit is the same list narrowed to the append-only security trail. --- README.md | 1 + go.mod | 2 +- go.sum | 2 + internal/cmd/activity.go | 95 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 internal/cmd/activity.go diff --git a/README.md b/README.md index a8792cc..38df879 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,7 @@ fopost analytics overview · top-posts · time-series fopost automations list · get · toggle · trigger · runs fopost webhooks list · create · test · delete fopost ads tree · pause · resume · insights · leads +fopost activity list · audit fopost completion bash · zsh · fish · powershell fopost version ``` diff --git a/go.mod b/go.mod index efaecb8..0eb9b7a 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/fopost/fopost-cli go 1.22 require ( - github.com/fopost/fopost-go v0.2.1-0.20260919224127-0a4908e7b1fc + github.com/fopost/fopost-go v0.2.1-0.20260920005547-4b2f43034ffd github.com/spf13/cobra v1.10.2 golang.org/x/term v0.27.0 ) diff --git a/go.sum b/go.sum index 66c7c85..314099e 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/fopost/fopost-go v0.2.1-0.20260919224127-0a4908e7b1fc h1:XzQsDXpqdmHo0fbAs07vVyESqW2fFC1WdNAPjHTssG8= github.com/fopost/fopost-go v0.2.1-0.20260919224127-0a4908e7b1fc/go.mod h1:Qz+7UCYTBnDEeZqB3VMrePxmYLVR9rFvx3+QWcKND8Q= +github.com/fopost/fopost-go v0.2.1-0.20260920005547-4b2f43034ffd h1:W3QJZjFgjCGqnwzzCbMmVbNcEbmNhV4EFvomBdpU2n8= +github.com/fopost/fopost-go v0.2.1-0.20260920005547-4b2f43034ffd/go.mod h1:Qz+7UCYTBnDEeZqB3VMrePxmYLVR9rFvx3+QWcKND8Q= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= diff --git a/internal/cmd/activity.go b/internal/cmd/activity.go new file mode 100644 index 0000000..925bbf5 --- /dev/null +++ b/internal/cmd/activity.go @@ -0,0 +1,95 @@ +package cmd + +import ( + fopost "github.com/fopost/fopost-go" + "github.com/spf13/cobra" + + "github.com/fopost/fopost-cli/internal/output" +) + +func init() { register(newActivityCmd) } + +func newActivityCmd(state *State) *cobra.Command { + cmd := &cobra.Command{ + Use: "activity", + Short: "Read what happened in a workspace, including the audit log", + } + cmd.AddCommand(newActivityListCmd(state), newActivityAuditCmd(state)) + return cmd +} + +func listActivity(state *State, cmd *cobra.Command, kind, cursor string, limit int) error { + client, err := state.Client() + if err != nil { + return err + } + resolved, err := state.Resolved() + if err != nil { + return err + } + page, err := client.Activity.List(cmd.Context(), &fopost.ListActivityParams{ + WorkspaceID: resolved.Workspace, + Kind: kind, + Cursor: cursor, + Limit: limit, + }) + if err != nil { + return err + } + printer := state.Printer() + return printer.Value(page, func() { + rows := make([][]string, 0, len(page.Events)) + for _, event := range page.Events { + actor := event.Actor.Name + if actor == "" { + actor = event.Actor.Type + } + rows = append(rows, []string{ + event.Time.String(), + event.Kind, + actor, + output.Truncate(event.Summary, 60), + }) + } + printer.Table([]string{"time", "kind", "actor", "summary"}, rows) + if page.NextCursor != "" { + printer.Success("More to read: pass --cursor %s.", page.NextCursor) + } + }) +} + +func newActivityListCmd(state *State) *cobra.Command { + var kind, cursor string + var limit int + cmd := &cobra.Command{ + Use: "list", + Short: "List activity, newest first", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return listActivity(state, cmd, kind, cursor, limit) + }, + } + cmd.Flags().StringVar(&kind, "kind", "", "publish, connection, webhook, inbox, automation, billing, or security") + cmd.Flags().StringVar(&cursor, "cursor", "", "next_cursor from the previous page") + cmd.Flags().IntVar(&limit, "limit", 0, "how many to return, 1 to 100") + return cmd +} + +func newActivityAuditCmd(state *State) *cobra.Command { + var cursor string + var limit int + cmd := &cobra.Command{ + Use: "audit", + Short: "The security audit log: who changed access, and when", + Long: "Members joining, leaving, or changing role and access, plus changes to two-step\n" + + "verification, passkeys, single sign-on, and signed-in devices. These rows are\n" + + "append-only and never expire.", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return listActivity(state, cmd, fopost.ActivityKindSecurity, cursor, limit) + }, + } + cmd.Flags().StringVar(&cursor, "cursor", "", "next_cursor from the previous page") + cmd.Flags().IntVar(&limit, "limit", 0, "how many to return, 1 to 100") + return cmd +}