-
Notifications
You must be signed in to change notification settings - Fork 193
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: audit log service * ARC-2643 add api router to fetch audit log * chore: audit log service * chore: audit log service * chore: PR review comments --------- Co-authored-by: Gary Xue <[email protected]> Co-authored-by: Gary Xue <[email protected]>
- Loading branch information
1 parent
300f5e5
commit 5060561
Showing
15 changed files
with
383 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,8 @@ GLOBAL_HASH_SECRET=testsecret | |
#Dyamno for deployment status | ||
DYNAMO_DEPLOYMENT_HISTORY_CACHE_TABLE_REGION=us-west-1 | ||
DYNAMO_DEPLOYMENT_HISTORY_CACHE_TABLE_NAME=deployment-history-cache | ||
DYNAMO_AUDIT_LOG_TABLE_REGION=us-west-1 | ||
DYNAMO_AUDIT_LOG_TABLE_NAME=audit-log | ||
|
||
# The Postgres URL used to connect to the database and secret for encrypting data | ||
DATABASE_URL=postgres://postgres:[email protected]:5432/jira-dev | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Router } from "express"; | ||
import { ApiAuditLogGetBySubscriptionId } from "./audit-log-get-by-sub-id"; | ||
import { param, query } from "express-validator"; | ||
import { returnOnValidationError } from "../api-utils"; | ||
|
||
export const AuditLogApiRouter = Router({ mergeParams: true }); | ||
|
||
AuditLogApiRouter.get("/subscription/:subscriptionId", | ||
param("subscriptionId").isInt(), | ||
query("entityType").isString(), | ||
query("entityId").isString(), | ||
query("issueKey").isString(), | ||
returnOnValidationError, | ||
ApiAuditLogGetBySubscriptionId | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import supertest from "supertest"; | ||
import { when } from "jest-when"; | ||
import { omit } from "lodash"; | ||
import { getFrontendApp } from "../../../app"; | ||
import { DatabaseStateCreator, CreatorResult } from "test/utils/database-state-creator"; | ||
import { findLog } from "services/audit-log-service"; | ||
|
||
jest.mock("services/audit-log-service"); | ||
|
||
describe("AuditLogApiGetBySubscriptionId", () => { | ||
|
||
const makeApiCall = (subscriptionId: string | number, params: Record<string, unknown>) => { | ||
return supertest(getFrontendApp()) | ||
.get(`/api/audit-log/subscription/${subscriptionId}`) | ||
.query(params) | ||
.set("X-Slauth-Mechanism", "test") | ||
.send(); | ||
}; | ||
|
||
let db: CreatorResult; | ||
let params; | ||
|
||
beforeEach(async () => { | ||
db = await new DatabaseStateCreator().forServer().create(); | ||
params = { | ||
issueKey: "ABC-123", | ||
entityType: "commit", | ||
entityId: "abcd-efgh-ijkl" | ||
}; | ||
}); | ||
|
||
describe.each(["issueKey", "entityType", "entityId"])("param validation", (paramKey) => { | ||
it(`should return 422 on missing param ${paramKey}`, async () => { | ||
await makeApiCall(db.subscription.id, omit(params, paramKey)) | ||
.expect(422); | ||
}); | ||
}); | ||
|
||
it(`should return error on missing subscription`, async () => { | ||
await makeApiCall(db.subscription.id + 1, params) | ||
.expect(500); | ||
}); | ||
|
||
|
||
it("should return audit log data successfully", async () => { | ||
|
||
when(findLog).calledWith({ | ||
subscriptionId: db.subscription.id, | ||
issueKey: "ABC-123", | ||
entityType: "commit", | ||
entityId: "abcd-efgh-ijkl" | ||
}, expect.anything()).mockResolvedValue({ | ||
name: "hello" | ||
} as any); | ||
|
||
const result = await makeApiCall(db.subscription.id, params).expect(200); | ||
|
||
expect(result.body).toEqual({ | ||
name: "hello" | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Request, Response } from "express"; | ||
import { Subscription } from "models/subscription"; | ||
import { findLog, AuditInfoPK } from "services/audit-log-service"; | ||
|
||
export const ApiAuditLogGetBySubscriptionId = async (req: Request, res: Response): Promise<void> => { | ||
|
||
const { subscriptionId } = req.params; | ||
const { issueKey, entityType, entityId } = req.query; | ||
|
||
const subscription = await Subscription.findByPk(subscriptionId); | ||
|
||
if (subscription === null) { | ||
throw new Error("Cannot find subscription by id " + subscriptionId); | ||
} | ||
|
||
const auditInfo: AuditInfoPK = { | ||
subscriptionId: Number(subscriptionId), | ||
issueKey: String(issueKey), | ||
entityType: String(entityType), | ||
entityId: String(entityId) | ||
}; | ||
|
||
const result = await findLog(auditInfo, req.log); | ||
|
||
res.status(200).json(result); | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { getLogger } from "config/logger"; | ||
import { envVars } from "config/env"; | ||
import { dynamodb as ddb } from "config/dynamodb"; | ||
import { createHashWithoutSharedSecret } from "utils/encryption"; | ||
import { auditLog, findLog } from "./audit-log-service"; | ||
|
||
const logger = getLogger("test"); | ||
const ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000; | ||
|
||
describe("audit log service", () => { | ||
describe("auditLog", () => { | ||
it("should successfully save DD api call audit info to dynamo db", async () => { | ||
const createdAt = new Date(); | ||
const subscriptionId = 241412; | ||
const entityId = "25e1008"; | ||
const entityAction = "pushed"; | ||
const entityType = "commit"; | ||
const source = "backfill"; | ||
const issueKey = "ARC-2605"; | ||
const ID = `subID_${subscriptionId}_typ_${entityType}_id_${entityId}_issKey_${issueKey}`; | ||
await auditLog( | ||
{ | ||
source, | ||
entityType, | ||
entityAction, | ||
entityId, | ||
subscriptionId, | ||
issueKey, | ||
createdAt | ||
}, | ||
logger | ||
); | ||
const result = await ddb | ||
.getItem({ | ||
TableName: envVars.DYNAMO_AUDIT_LOG_TABLE_NAME, | ||
Key: { | ||
Id: { S: createHashWithoutSharedSecret(ID) }, | ||
CreatedAt: { N: String(createdAt.getTime()) } | ||
}, | ||
AttributesToGet: [ | ||
"Id", | ||
"CreatedAt", | ||
"ExpiredAfter", | ||
"source", | ||
"entityType", | ||
"entityAction", | ||
"entityId", | ||
"subscriptionId", | ||
"issueKey" | ||
] | ||
}) | ||
.promise(); | ||
expect(result.$response.error).toBeNull(); | ||
expect(result.Item).toEqual({ | ||
Id: { S: createHashWithoutSharedSecret(ID) }, | ||
CreatedAt: { N: String(createdAt.getTime()) }, | ||
ExpiredAfter: { | ||
N: String( | ||
Math.floor((createdAt.getTime() + ONE_DAY_IN_MILLISECONDS) / 1000) | ||
) | ||
}, | ||
source: { S: source }, | ||
entityAction: { S: entityAction }, | ||
entityId: { S: entityId }, | ||
entityType: { S: entityType }, | ||
issueKey: { S: issueKey }, | ||
subscriptionId: { N: String(subscriptionId) } | ||
}); | ||
}); | ||
|
||
describe("auditLog", () => { | ||
it("should successfully save DD api call audit info to dynamo db", async () => { | ||
const createdAt = new Date(); | ||
const subscriptionId = 241412; | ||
const entityId = "25e1008"; | ||
const entityAction = "pushed"; | ||
const entityType = "commit"; | ||
const source = "backfill"; | ||
const issueKey = "ARC-2605"; | ||
await auditLog( | ||
{ | ||
source, | ||
entityType, | ||
entityAction, | ||
entityId, | ||
subscriptionId, | ||
issueKey, | ||
createdAt | ||
}, | ||
logger | ||
); | ||
const result = await findLog( | ||
{ | ||
entityType, | ||
entityId, | ||
subscriptionId, | ||
issueKey | ||
}, | ||
logger | ||
); | ||
expect(result).toEqual([{ | ||
entityAction, | ||
entityId, | ||
entityType, | ||
issueKey, | ||
source, | ||
subscriptionId, | ||
createdAt | ||
}]); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.