Skip to content

Commit

Permalink
Improve DefectDojo API client
Browse files Browse the repository at this point in the history
  • Loading branch information
GaelGirodon committed Nov 29, 2022
1 parent 3ef28a5 commit 00c8c18
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 34 deletions.
26 changes: 14 additions & 12 deletions src/defectdojo.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ export class DefectDojoApiClient {
*/
constructor(url, token) {
this.url = url.replace(/\/$/, "");
this.apiUrl = this.url + "/api/v2";
this.options = { "headers": { "Authorization": `Token ${token}` } };
this.http = axios.create({
baseURL: `${this.url}/api/v2`,
headers: { "Authorization": `Token ${token}` }
});
}

/**
Expand All @@ -32,12 +34,12 @@ export class DefectDojoApiClient {
async getProduct(name) {
console.log(`[info] Fetching product '${name}'`)
try {
const response = await axios.get(`${this.apiUrl}/products?name=${name}`, this.options);
const data = response.data;
if (data?.count !== 1) {
const response = await this.http.get(`/products?name=${name}`);
const results = response.data?.results?.filter(p => p.name === name); // Exact match
if (results?.length !== 1) {
throw new Error("expected to find a single product");
}
const product = data.results[0];
const product = results[0];
product.title = product.description || product.name;
product.url = `${this.url}/product/${product.id}`;
console.log(`[info] Product id = ${product.id}`);
Expand All @@ -58,12 +60,12 @@ export class DefectDojoApiClient {
async getEngagement(productId, name) {
console.log(`[info] Fetching engagement '${name}' for product id '${productId}'`);
try {
const response = await axios.get(`${this.apiUrl}/engagements?product=${productId}&name=${name}`, this.options);
const data = response.data;
if (data?.count !== 1) {
const response = await this.http.get(`/engagements?product=${productId}&name=${name}`);
const results = response.data?.results?.filter(e => e.name === name); // Exact match
if (results?.length !== 1) {
throw new Error("expected to find a single engagement");
}
const engagement = data.results[0];
const engagement = results[0];
engagement.url = `${this.url}/engagement/${engagement.id}`;
console.log(`[info] Engagement id = ${engagement.id}`);
return engagement;
Expand All @@ -84,13 +86,13 @@ export class DefectDojoApiClient {
console.log(`[info] Fetching findings for engagement(s) ${engagements.join(", ")}`);
try {
const filters = statuses.map(s => s[0] !== "!" ? s + "=true" : s.slice(1) + "=false").join("&");
let findingsUrl = `${this.apiUrl}/findings?test__engagement=${engagements.join(",")}`
let findingsUrl = `/findings?test__engagement=${engagements.join(",")}`
+ `&limit=100&${filters}&related_fields=true`;
const findings = [];
let findingsPage = 0;
while (findingsUrl && findingsPage < 20) {
console.log(`[info] Fetching findings (page ${findingsPage}): ${findingsUrl}`);
let findingsResponse = await axios.get(findingsUrl, this.options);
let findingsResponse = await this.http.get(findingsUrl);
let findingsData = findingsResponse.data;
findings.push(...findingsData.results);
findingsUrl = findingsData.next;
Expand Down
2 changes: 1 addition & 1 deletion test/defectdojo.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("DefectDojoApiClient", function () {
describe("#getEngagement()", function () {
it("should return a single engagement", async function () {
let engagement;
await assert.doesNotReject(async () => engagement = await client.getEngagement("main"));
await assert.doesNotReject(async () => engagement = await client.getEngagement(1, "main"));
assert.strictEqual(engagement.id, 1);
assert.strictEqual(engagement.url, "http://localhost:8888/engagement/1");
});
Expand Down
38 changes: 17 additions & 21 deletions test/stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,28 @@ const findings = JSON.parse(readFileSync(
{ encoding: "utf8" })
);

// Authentication stub
app.use((req, res, next) => {
if (!req.headers.authorization) {
return res.status(401).send("Unauthorized");
}
next();
});

// GET /api/v2/products should return a single test product.
app.get("/api/v2/products", (req, res) => {
if (req.query.name === "unknown") {
res.json({ count: 0, results: [] });
return;
}
res.json({
count: 1,
results: [
{ id: 1, name: "product", description: "Product description" }
]
});
const results = [
{ id: 1, name: "product", description: "Product description" }
].filter(p => !req.params.name || p.name.includes(req.params.name));
res.json({ count: results.length, results });
});

// GET /api/v2/engagements should return a single test engagement.
app.get("/api/v2/engagements", (req, res) => {
if (req.query.name === "unknown") {
res.json({ count: 0, results: [] });
return;
}
res.json({
count: 1,
results: [
{ id: 1, name: "main" }
]
});
const results = [
{ id: 1, name: "main" }
].filter(e => !req.params.name || e.name.includes(req.params.name));
res.json({ count: results.length, results });
});

// GET /api/v2/engagements should return some test findings.
Expand All @@ -50,7 +46,7 @@ app.get("/api/v2/findings", (req, res) => {
return;
}
res.json({
count: 1,
count: findings.length,
results: findings
});
});
Expand Down

0 comments on commit 00c8c18

Please sign in to comment.