mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
chore: mark workspace apps and workspace agents as unaudited (#18761)
The main goal of this PR is to remove Workspace Apps and Workspace Agents from the auto-generated audit log documentation, that incorrectly claims they are audited resources (no longer true with the addition of the connection log). Though I believe we haven't touched any codepaths for returning audit logs, this PR also adds a test that ensures we continue to return *existing* connection, disconnect and open events correctly from the audit log API.
This commit is contained in:
@@ -31,9 +31,7 @@ type Auditable interface {
|
||||
database.NotificationTemplate |
|
||||
idpsync.OrganizationSyncSettings |
|
||||
idpsync.GroupSyncSettings |
|
||||
idpsync.RoleSyncSettings |
|
||||
database.WorkspaceAgent |
|
||||
database.WorkspaceApp
|
||||
idpsync.RoleSyncSettings
|
||||
}
|
||||
|
||||
// Map is a map of changed fields in an audited resource. It maps field names to
|
||||
|
||||
@@ -131,10 +131,6 @@ func ResourceTarget[T Auditable](tgt T) string {
|
||||
return "Organization Group Sync"
|
||||
case idpsync.RoleSyncSettings:
|
||||
return "Organization Role Sync"
|
||||
case database.WorkspaceAgent:
|
||||
return typed.Name
|
||||
case database.WorkspaceApp:
|
||||
return typed.Slug
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown resource %T for ResourceTarget", tgt))
|
||||
}
|
||||
@@ -197,10 +193,6 @@ func ResourceID[T Auditable](tgt T) uuid.UUID {
|
||||
return noID // Org field on audit log has org id
|
||||
case idpsync.RoleSyncSettings:
|
||||
return noID // Org field on audit log has org id
|
||||
case database.WorkspaceAgent:
|
||||
return typed.ID
|
||||
case database.WorkspaceApp:
|
||||
return typed.ID
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown resource %T for ResourceID", tgt))
|
||||
}
|
||||
@@ -254,10 +246,6 @@ func ResourceType[T Auditable](tgt T) database.ResourceType {
|
||||
return database.ResourceTypeIdpSyncSettingsRole
|
||||
case idpsync.GroupSyncSettings:
|
||||
return database.ResourceTypeIdpSyncSettingsGroup
|
||||
case database.WorkspaceAgent:
|
||||
return database.ResourceTypeWorkspaceAgent
|
||||
case database.WorkspaceApp:
|
||||
return database.ResourceTypeWorkspaceApp
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown resource %T for ResourceType", typed))
|
||||
}
|
||||
@@ -314,10 +302,6 @@ func ResourceRequiresOrgID[T Auditable]() bool {
|
||||
return true
|
||||
case idpsync.RoleSyncSettings:
|
||||
return true
|
||||
case database.WorkspaceAgent:
|
||||
return true
|
||||
case database.WorkspaceApp:
|
||||
return true
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown resource %T for ResourceRequiresOrgID", tgt))
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/audit"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbgen"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/provisioner/echo"
|
||||
@@ -531,3 +532,112 @@ func completeWithAgentAndApp() *echo.Responses {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TestDeprecatedConnEvents tests the deprecated connection and disconnection
|
||||
// events in the audit logs. These events are no longer created, but need to be
|
||||
// returned by the API.
|
||||
func TestDeprecatedConnEvents(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
ctx = context.Background()
|
||||
client, _, api = coderdtest.NewWithAPI(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
||||
user = coderdtest.CreateFirstUser(t, client)
|
||||
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, completeWithAgentAndApp())
|
||||
template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
)
|
||||
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, template.ID)
|
||||
workspace.LatestBuild = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
|
||||
|
||||
type additionalFields struct {
|
||||
audit.AdditionalFields
|
||||
ConnectionType string `json:"connection_type"`
|
||||
}
|
||||
|
||||
sshFields := additionalFields{
|
||||
AdditionalFields: audit.AdditionalFields{
|
||||
WorkspaceName: workspace.Name,
|
||||
BuildNumber: "999",
|
||||
BuildReason: "initiator",
|
||||
WorkspaceOwner: workspace.OwnerName,
|
||||
WorkspaceID: workspace.ID,
|
||||
},
|
||||
ConnectionType: "SSH",
|
||||
}
|
||||
|
||||
sshFieldsBytes, err := json.Marshal(sshFields)
|
||||
require.NoError(t, err)
|
||||
|
||||
appFields := audit.AdditionalFields{
|
||||
WorkspaceName: workspace.Name,
|
||||
// Deliberately empty
|
||||
BuildNumber: "",
|
||||
BuildReason: "",
|
||||
WorkspaceOwner: workspace.OwnerName,
|
||||
WorkspaceID: workspace.ID,
|
||||
}
|
||||
|
||||
appFieldsBytes, err := json.Marshal(appFields)
|
||||
require.NoError(t, err)
|
||||
|
||||
dbgen.AuditLog(t, api.Database, database.AuditLog{
|
||||
OrganizationID: user.OrganizationID,
|
||||
Action: database.AuditActionConnect,
|
||||
ResourceType: database.ResourceTypeWorkspaceAgent,
|
||||
ResourceID: workspace.LatestBuild.Resources[0].Agents[0].ID,
|
||||
ResourceTarget: workspace.LatestBuild.Resources[0].Agents[0].Name,
|
||||
Time: time.Date(2022, 8, 15, 14, 30, 45, 100, time.UTC), // 2022-8-15 14:30:45
|
||||
AdditionalFields: sshFieldsBytes,
|
||||
})
|
||||
|
||||
dbgen.AuditLog(t, api.Database, database.AuditLog{
|
||||
OrganizationID: user.OrganizationID,
|
||||
Action: database.AuditActionDisconnect,
|
||||
ResourceType: database.ResourceTypeWorkspaceAgent,
|
||||
ResourceID: workspace.LatestBuild.Resources[0].Agents[0].ID,
|
||||
ResourceTarget: workspace.LatestBuild.Resources[0].Agents[0].Name,
|
||||
Time: time.Date(2022, 8, 15, 14, 35, 0o0, 100, time.UTC), // 2022-8-15 14:35:00
|
||||
AdditionalFields: sshFieldsBytes,
|
||||
})
|
||||
|
||||
dbgen.AuditLog(t, api.Database, database.AuditLog{
|
||||
OrganizationID: user.OrganizationID,
|
||||
UserID: user.UserID,
|
||||
Action: database.AuditActionOpen,
|
||||
ResourceType: database.ResourceTypeWorkspaceApp,
|
||||
ResourceID: workspace.LatestBuild.Resources[0].Agents[0].Apps[0].ID,
|
||||
ResourceTarget: workspace.LatestBuild.Resources[0].Agents[0].Apps[0].Slug,
|
||||
Time: time.Date(2022, 8, 15, 14, 30, 45, 100, time.UTC), // 2022-8-15 14:30:45
|
||||
AdditionalFields: appFieldsBytes,
|
||||
})
|
||||
|
||||
connLog, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{
|
||||
SearchQuery: "action:connect",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, connLog.AuditLogs, 1)
|
||||
var sshOutFields additionalFields
|
||||
err = json.Unmarshal(connLog.AuditLogs[0].AdditionalFields, &sshOutFields)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sshFields, sshOutFields)
|
||||
|
||||
dcLog, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{
|
||||
SearchQuery: "action:disconnect",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, dcLog.AuditLogs, 1)
|
||||
err = json.Unmarshal(dcLog.AuditLogs[0].AdditionalFields, &sshOutFields)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sshFields, sshOutFields)
|
||||
|
||||
openLog, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{
|
||||
SearchQuery: "action:open",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, openLog.AuditLogs, 1)
|
||||
var appOutFields audit.AdditionalFields
|
||||
err = json.Unmarshal(openLog.AuditLogs[0].AdditionalFields, &appOutFields)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, appFields, appOutFields)
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func AuditLog(t testing.TB, db database.Store, seed database.AuditLog) database.
|
||||
Action: takeFirst(seed.Action, database.AuditActionCreate),
|
||||
Diff: takeFirstSlice(seed.Diff, []byte("{}")),
|
||||
StatusCode: takeFirst(seed.StatusCode, 200),
|
||||
AdditionalFields: takeFirstSlice(seed.Diff, []byte("{}")),
|
||||
AdditionalFields: takeFirstSlice(seed.AdditionalFields, []byte("{}")),
|
||||
RequestID: takeFirst(seed.RequestID, uuid.New()),
|
||||
ResourceIcon: takeFirst(seed.ResourceIcon, ""),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user