Skip to content

Commit

Permalink
Draft: Audit log GraphQL API
Browse files Browse the repository at this point in the history
codegen setup

fix some

some

some

some

more

?

??

SOME?

??

?

fix some?

SOME

???

more

some some

test

fix some code review!

?

fix some

clean!

fix codegen path

???

?

??

?

?

added scope ti auditlogmanager

scheme publish & check & delete

members role

CLEAN MORE

target

project

prettier

fix resolver schema published

lint

fix code review!

?

?

prettier

migration

fix!

clean

fix filters

clean

??

?

resolve user

eventTime: e => e.event_time,

    scalar DateTime

  user: e => {

eventTime

clean

changes

Fix up mapper names and types.next imports

fix resolvers :)

clean all

lint

clean

sentry

fix some code review

more and more

Support && Laboratory Collection

CRUD query in collection

User role

org and target

fix code review

resolvers again!

prettier

clean

revert `inviteToOrganizationByEmail`

revert `updateSchemaPolicyForProject`

user invite

action for clickhouse

remove `await` from schema

fix code review

lint

graphql comments

schema + app deployment

fix

some

clean and clear

some and some

basic test

fix

fix rebase and conflicts

fix error

fix code review

?

some

some fixes
  • Loading branch information
TuvalSimha committed Oct 24, 2024
1 parent a5eb78a commit bd3caff
Show file tree
Hide file tree
Showing 109 changed files with 3,348 additions and 37 deletions.
1 change: 1 addition & 0 deletions codegen.mts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const config: CodegenConfig = {
excludeTypes: [
'TokenInfoPayload',
'OrganizationByInviteCodePayload',
'AuditLog',
'JoinOrganizationPayload',
'Schema',
'GraphQLNamedType',
Expand Down
41 changes: 41 additions & 0 deletions integration-tests/tests/api/audit-log/creation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { graphql } from 'testkit/gql';
import { execute } from '../../../testkit/graphql';
import { initSeed } from '../../../testkit/seed';

describe('Audit Logs Creation', () => {
describe('Organization', () => {
const query = graphql(`
query MyQuery($selector: OrganizationSelectorInput!) {
auditLogs(selector: $selector) {
nodes {
eventTime
id
__typename
}
}
}
`);
test.concurrent(
'Should be only one audit log for organization creation',
async ({ expect }) => {
const { ownerToken, createOrg } = await initSeed().createOwner();
const { organization } = await createOrg();

const result = await execute({
document: query,
variables: {
selector: {
organization: organization.id,
},
},
authToken: ownerToken,
});
expect(result.rawBody.data?.auditLogs.nodes).not.toBeNull();
expect(result.rawBody.data?.auditLogs.nodes.length).toBeGreaterThan(0);
expect(result.rawBody.data?.auditLogs.nodes[0].__typename).toBe(
'OrganizationCreatedAuditLog',
);
},
);
});
});
20 changes: 20 additions & 0 deletions packages/migrations/src/clickhouse-actions/011-audit-logs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Action } from '../clickhouse';

export const action: Action = async exec => {
await exec(`
CREATE TABLE IF NOT EXISTS "audit_log"
(
"id" UUID DEFAULT generateUUIDv4() CODEC(ZSTD(1)),
"event_time" DateTime CODEC(ZSTD(1)),
"user_id" String CODEC(ZSTD(1)),
"user_email" String CODEC(ZSTD(1)),
"organization_id" String CODEC(ZSTD(1)),
"event_action" String CODEC(ZSTD(1)),
"metadata" String CODEC(ZSTD(1))
)
ENGINE = ReplacingMergeTree
ORDER BY ("event_time", "user_id", "organization_id")
TTL event_time + INTERVAL 1 YEAR
SETTINGS index_granularity = 8192
`);
};
1 change: 1 addition & 0 deletions packages/migrations/src/clickhouse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ export async function migrateClickHouse(
import('./clickhouse-actions/008-daily-operations-log'),
import('./clickhouse-actions/009-ttl-1-year'),
import('./clickhouse-actions/010-app-deployment-operations'),
import('./clickhouse-actions/011-audit-logs'),
]);

async function actionRunner(action: Action, index: number) {
Expand Down
2 changes: 2 additions & 0 deletions packages/services/api/src/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { alertsModule } from './modules/alerts';
import { WEBHOOKS_CONFIG, WebhooksConfig } from './modules/alerts/providers/tokens';
import { appDeploymentsModule } from './modules/app-deployments';
import { APP_DEPLOYMENTS_ENABLED } from './modules/app-deployments/providers/app-deployments-enabled-token';
import { auditLogsModule } from './modules/audit-logs';
import { authModule } from './modules/auth';
import { billingModule } from './modules/billing';
import { BILLING_CONFIG, BillingConfig } from './modules/billing/providers/tokens';
Expand Down Expand Up @@ -82,6 +83,7 @@ const modules = [
integrationsModule,
alertsModule,
feedbackModule,
auditLogsModule,
cdnModule,
adminModule,
usageEstimationModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable, Scope } from 'graphql-modules';
import { batch } from '@theguild/buddy';
import { Target } from '../../../shared/entities';
import { AuditLogManager } from '../../audit-logs/providers/audit-logs-manager';
import { AuthManager } from '../../auth/providers/auth-manager';
import { TargetAccessScope } from '../../auth/providers/scopes';
import { Logger } from '../../shared/providers/logger';
Expand All @@ -23,6 +24,7 @@ export class AppDeploymentsManager {
private tokenStorage: TokenStorage,
private targetManager: TargetManager,
private appDeployments: AppDeployments,
private auditLogManager: AuditLogManager,
) {
this.logger = logger.child({ source: 'AppDeploymentsManager' });
}
Expand Down Expand Up @@ -82,11 +84,31 @@ export class AppDeploymentsManager {
scope: TargetAccessScope.REGISTRY_WRITE,
});

return await this.appDeployments.createAppDeployment({
const result = await this.appDeployments.createAppDeployment({
organizationId: tokenRecord.organization,
targetId: tokenRecord.target,
appDeployment: args.appDeployment,
});

const currentUser = await this.auth.getCurrentUser();
await this.auditLogManager.createLogAuditEvent(
{
eventType: 'APP_DEPLOYMENT_CREATED',
appDeploymentCreatedAuditLogSchema: {
deploymentId: result.appDeployment ? result.appDeployment.id : null,
deploymentName: result.appDeployment ? result.appDeployment.name : null,
deploymentVersion: result.appDeployment ? result.appDeployment.version : null,
},
},
{
userId: currentUser.id,
userEmail: currentUser.email,
organizationId: tokenRecord.organization,
user: currentUser,
},
);

return result;
}

async addDocumentsToAppDeployment(args: {
Expand All @@ -109,13 +131,36 @@ export class AppDeploymentsManager {
scope: TargetAccessScope.REGISTRY_WRITE,
});

return await this.appDeployments.addDocumentsToAppDeployment({
const result = await this.appDeployments.addDocumentsToAppDeployment({
organizationId: tokenRecord.organization,
projectId: tokenRecord.project,
targetId: tokenRecord.target,
appDeployment: args.appDeployment,
operations: args.documents,
});

const currentUser = await this.auth.getCurrentUser();
await this.auditLogManager.createLogAuditEvent(
{
eventType: 'APP_DEPLOYMENT_UPDATED',
appDeploymentUpdatedAuditLogSchema: {
deploymentId: result.appDeployment ? result.appDeployment.id : null,
updatedFields: JSON.stringify({
name: result.appDeployment?.name,
version: result.appDeployment?.version,
documents: args.documents,
}),
},
},
{
organizationId: tokenRecord.organization,
userId: currentUser.id,
userEmail: currentUser.email,
user: currentUser,
},
);

return result;
}

async activateAppDeployment(args: {
Expand All @@ -134,11 +179,34 @@ export class AppDeploymentsManager {
scope: TargetAccessScope.REGISTRY_WRITE,
});

return await this.appDeployments.activateAppDeployment({
const result = await this.appDeployments.activateAppDeployment({
organizationId: tokenRecord.organization,
targetId: tokenRecord.target,
appDeployment: args.appDeployment,
});

const currentUser = await this.auth.getCurrentUser();
await this.auditLogManager.createLogAuditEvent(
{
eventType: 'APP_DEPLOYMENT_UPDATED',
appDeploymentUpdatedAuditLogSchema: {
deploymentId: result.appDeployment ? result.appDeployment.id : null,
updatedFields: JSON.stringify({
name: args.appDeployment.name,
version: args.appDeployment.version,
status: 'ACTIVATED',
}),
},
},
{
organizationId: tokenRecord.organization,
userId: currentUser.id,
userEmail: currentUser.email,
user: currentUser,
},
);

return;
}

async retireAppDeployment(args: {
Expand All @@ -157,11 +225,34 @@ export class AppDeploymentsManager {
scope: TargetAccessScope.REGISTRY_WRITE,
});

return await this.appDeployments.retireAppDeployment({
const result = await this.appDeployments.retireAppDeployment({
organizationId: target.orgId,
targetId: target.id,
appDeployment: args.appDeployment,
});

const currentUser = await this.auth.getCurrentUser();
await this.auditLogManager.createLogAuditEvent(
{
eventType: 'APP_DEPLOYMENT_UPDATED',
appDeploymentUpdatedAuditLogSchema: {
deploymentId: result.appDeployment?.id,
updatedFields: JSON.stringify({
name: result.appDeployment?.name,
version: result.appDeployment?.version,
status: 'RETIRED',
}),
},
},
{
userId: currentUser.id,
userEmail: currentUser.email,
organizationId: target.orgId,
user: currentUser,
},
);

return result;
}

async getPaginatedDocumentsForAppDeployment(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AuditLogManager } from '../../../audit-logs/providers/audit-logs-manager';
import { AuthManager } from '../../../auth/providers/auth-manager';
import { AppDeploymentsManager } from '../../providers/app-deployments-manager';
import type { MutationResolvers } from './../../../../__generated__/types.next';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AuditLogManager } from '../../../audit-logs/providers/audit-logs-manager';
import { AuthManager } from '../../../auth/providers/auth-manager';
import { AppDeploymentsManager } from '../../providers/app-deployments-manager';
import type { MutationResolvers } from './../../../../__generated__/types.next';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AuditLogManager } from '../../../audit-logs/providers/audit-logs-manager';
import { AuthManager } from '../../../auth/providers/auth-manager';
import { AppDeploymentsManager } from '../../providers/app-deployments-manager';
import type { MutationResolvers } from './../../../../__generated__/types.next';

Expand Down
13 changes: 13 additions & 0 deletions packages/services/api/src/modules/audit-logs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createModule } from 'graphql-modules';
import { ClickHouse } from '../operations/providers/clickhouse-client';
import { AuditLogManager } from './providers/audit-logs-manager';
import { resolvers } from './resolvers.generated';
import { typeDefs } from './module.graphql';

export const auditLogsModule = createModule({
id: 'audit-logs',
dirname: __dirname,
typeDefs,
resolvers,
providers: [AuditLogManager, ClickHouse],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { AuditLogModel } from './providers/audit-logs-manager';

export type AuditLogMapper = AuditLogModel;
// Schema
export type SchemaPolicySettingsUpdatedAuditLogMapper = AuditLogModel;
export type SchemaCheckedAuditLogMapper = AuditLogModel;
export type SchemaPublishAuditLogMapper = AuditLogModel;
export type ServiceDeletedAuditLogMapper = AuditLogModel;
// Organization
export type OrganizationSettingsUpdatedAuditLogMapper = AuditLogModel;
export type OrganizationTransferredAuditLogMapper = AuditLogModel;
export type OrganizationTransferredRequestAuditLogMapper = AuditLogModel;
export type OrganizationCreatedAuditLogMapper = AuditLogModel;
export type OrganizationDeletedAuditLogMapper = AuditLogModel;
export type OrganizationUpdatedIntegrationAuditLogMapper = AuditLogModel;
// Project
export type ProjectCreatedAuditLogMapper = AuditLogModel;
export type ProjectSettingsUpdatedAuditLogMapper = AuditLogModel;
export type ProjectDeletedAuditLogMapper = AuditLogModel;
// User Role
export type RoleCreatedAuditLogMapper = AuditLogModel;
export type RoleAssignedAuditLogMapper = AuditLogModel;
export type RoleDeletedAuditLogMapper = AuditLogModel;
export type RoleUpdatedAuditLogMapper = AuditLogModel;
// Support
export type SupportTicketCreatedAuditLogMapper = AuditLogModel;
export type SupportTicketUpdatedAuditLogMapper = AuditLogModel;
// Laboratory Collection
export type CollectionCreatedAuditLogMapper = AuditLogModel;
export type CollectionDeletedAuditLogMapper = AuditLogModel;
export type CollectionUpdatedAuditLogMapper = AuditLogModel;
// Laboratory Collection Operation
export type OperationInDocumentCollectionCreatedAuditLogMapper = AuditLogModel;
export type OperationInDocumentCollectionUpdatedAuditLogMapper = AuditLogModel;
export type OperationInDocumentCollectionDeletedAuditLogMapper = AuditLogModel;
// User
export type UserInvitedAuditLogMapper = AuditLogModel;
export type UserJoinedAuditLogMapper = AuditLogModel;
export type UserRemovedAuditLogMapper = AuditLogModel;
export type UserSettingsUpdatedAuditLogMapper = AuditLogModel;
// Target
export type TargetCreatedAuditLogMapper = AuditLogModel;
export type TargetSettingsUpdatedAuditLogMapper = AuditLogModel;
export type TargetDeletedAuditLogMapper = AuditLogModel;
// Subscription
export type SubscriptionCreatedAuditLogMapper = AuditLogModel;
export type SubscriptionUpdatedAuditLogMapper = AuditLogModel;
export type SubscriptionCanceledAuditLogMapper = AuditLogModel;
// App Deployment
export type AppDeploymentCreatedAuditLogMapper = AuditLogModel;
export type AppDeploymentUpdatedAuditLogMapper = AuditLogModel;
export type AppDeploymentPublishedAuditLogMapper = AuditLogModel;
Loading

0 comments on commit bd3caff

Please sign in to comment.