Ctrl K
ComunidadGuías…

coderd/audit_internal_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package coderd

import (
	"context"
	"database/sql"
	"encoding/json"
	"testing"

	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	"cdr.dev/slog/v3/sloggers/slogtest"
	"github.com/coder/coder/v2/coderd/database"
	"github.com/coder/coder/v2/coderd/database/dbauthz"
	"github.com/coder/coder/v2/coderd/database/dbmock"
	"github.com/coder/coder/v2/codersdk"
)

func TestAuditLogIsResourceDeleted(t *testing.T) {
	t.Parallel()

	for _, tc := range []struct {
		name        string
		err         error
		wantDeleted bool
	}{
		{name: "AnError", err: assert.AnError, wantDeleted: false},
		{name: "NotAuthorized", err: dbauthz.NotAuthorizedError{}, wantDeleted: false},
		{name: "NoError", err: nil, wantDeleted: false},
		{name: "NoRows", err: sql.ErrNoRows, wantDeleted: true},
	} {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			ctrl := gomock.NewController(t)
			db := dbmock.NewMockStore(ctrl)
			chatID := uuid.New()
			db.EXPECT().GetChatByID(gomock.Any(), chatID).Return(database.Chat{}, tc.err)

			api := &API{
				Options: &Options{Database: db, Logger: slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})},
			}

			deleted := api.auditLogIsResourceDeleted(context.Background(), database.GetAuditLogsOffsetRow{
				AuditLog: database.AuditLog{ResourceType: database.ResourceTypeChat, ResourceID: chatID},
			})
			require.Equal(t, tc.wantDeleted, deleted)
		})
	}
}

func TestAuditLogDescription(t *testing.T) {
	t.Parallel()
	testCases := []struct {
		name string
		alog database.GetAuditLogsOffsetRow
		want string
	}{
		{
			name: "mainline",
			alog: database.GetAuditLogsOffsetRow{
				AuditLog: database.AuditLog{
					Action:       database.AuditActionCreate,
					StatusCode:   200,
					ResourceType: database.ResourceTypeWorkspace,
				},
			},
			want: "{user} created workspace {target}",
		},
		{
			name: "unsuccessful",
			alog: database.GetAuditLogsOffsetRow{
				AuditLog: database.AuditLog{
					Action:       database.AuditActionCreate,
					StatusCode:   400,
					ResourceType: database.ResourceTypeWorkspace,
				},
			},
			want: "{user} unsuccessfully attempted to create workspace {target}",
		},
		{
			name: "login",
			alog: database.GetAuditLogsOffsetRow{
				AuditLog: database.AuditLog{
					Action:       database.AuditActionLogin,
					StatusCode:   200,
					ResourceType: database.ResourceTypeApiKey,
				},
			},
			want: "{user} logged in",
		},
		{
			name: "unsuccessful_login",
			alog: database.GetAuditLogsOffsetRow{
				AuditLog: database.AuditLog{
					Action:       database.AuditActionLogin,
					StatusCode:   401,
					ResourceType: database.ResourceTypeApiKey,
				},
			},
			want: "{user} unsuccessfully attempted to login",
		},
		{
			name: "gitsshkey",
			alog: database.GetAuditLogsOffsetRow{
				AuditLog: database.AuditLog{
					Action:       database.AuditActionDelete,
					StatusCode:   200,
					ResourceType: database.ResourceTypeGitSshKey,
				},
			},
			want: "{user} deleted the git ssh key",
		},
		{
			name: "chat_archived",
			alog: chatAuditLogRow(t, codersdk.AuditDiff{
				"archived": {Old: false, New: true},
			}),
			want: "{user} archived chat {target}",
		},
		{
			name: "chat_unarchived",
			alog: chatAuditLogRow(t, codersdk.AuditDiff{
				"archived": {Old: true, New: false},
			}),
			want: "{user} unarchived chat {target}",
		},
		{
			name: "chat_sharing_user_acl",
			alog: chatAuditLogRow(t, codersdk.AuditDiff{
				"user_acl": {Old: map[string]any{}, New: map[string]any{"user-1": map[string]any{"permissions": []string{"read"}}}},
			}),
			want: "{user} updated sharing for chat {target}",
		},
		{
			name: "chat_sharing_group_acl",
			alog: chatAuditLogRow(t, codersdk.AuditDiff{
				"group_acl": {Old: map[string]any{}, New: map[string]any{"group-1": map[string]any{"permissions": []string{"read"}}}},
			}),
			want: "{user} updated sharing for chat {target}",
		},
		{
			name: "chat_sharing_both_acls",
			alog: chatAuditLogRow(t, codersdk.AuditDiff{
				"user_acl":  {Old: map[string]any{}, New: map[string]any{"user-1": map[string]any{"permissions": []string{"read"}}}},
				"group_acl": {Old: map[string]any{}, New: map[string]any{"group-1": map[string]any{"permissions": []string{"read"}}}},
			}),
			want: "{user} updated sharing for chat {target}",
		},
		{
			name: "chat_mixed_diff_falls_through",
			alog: chatAuditLogRow(t, codersdk.AuditDiff{
				"archived":  {Old: false, New: true},
				"pin_order": {Old: 1, New: 0},
			}),
			want: "{user} updated chat {target}",
		},
		{
			name: "chat_acl_with_extra_field_falls_through",
			alog: chatAuditLogRow(t, codersdk.AuditDiff{
				"user_acl":  {Old: map[string]any{}, New: map[string]any{}},
				"pin_order": {Old: 1, New: 0},
			}),
			want: "{user} updated chat {target}",
		},
		{
			name: "chat_failed_write_no_override",
			alog: func() database.GetAuditLogsOffsetRow {
				row := chatAuditLogRow(t, codersdk.AuditDiff{
					"archived": {Old: false, New: true},
				})
				row.AuditLog.StatusCode = 400
				return row
			}(),
			want: "{user} unsuccessfully attempted to write chat {target}",
		},
		{
			name: "chat_redirect_no_override",
			alog: func() database.GetAuditLogsOffsetRow {
				row := chatAuditLogRow(t, codersdk.AuditDiff{
					"archived": {Old: false, New: true},
				})
				row.AuditLog.StatusCode = 303
				return row
			}(),
			want: "{user} was redirected attempting to write chat {target}",
		},
		{
			name: "chat_non_write_action_no_override",
			alog: func() database.GetAuditLogsOffsetRow {
				row := chatAuditLogRow(t, codersdk.AuditDiff{
					"user_acl": {Old: map[string]any{}, New: map[string]any{"user-1": map[string]any{"permissions": []string{"read"}}}},
				})
				row.AuditLog.Action = database.AuditActionCreate
				return row
			}(),
			want: "{user} created chat {target}",
		},
	}
	// nolint: paralleltest // no longer need to reinitialize loop vars in go 1.22
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()
			got := auditLogDescription(tc.alog)
			require.Equal(t, tc.want, got)
		})
	}
}

// chatAuditLogRow builds a GetAuditLogsOffsetRow for a successful chat write
// with the given diff, suitable for testing auditLogDescription.
func chatAuditLogRow(t *testing.T, diff codersdk.AuditDiff) database.GetAuditLogsOffsetRow {
	t.Helper()
	rawDiff, err := json.Marshal(diff)
	require.NoError(t, err)
	return database.GetAuditLogsOffsetRow{
		AuditLog: database.AuditLog{
			Action:       database.AuditActionWrite,
			StatusCode:   200,
			ResourceType: database.ResourceTypeChat,
			Diff:         rawDiff,
		},
	}
}