Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 35 additions & 27 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,25 @@
"@opentelemetry/instrumentation-express": "^0.59.0",
"@opentelemetry/instrumentation-http": "^0.211.0",
"@opentelemetry/instrumentation-winston": "^0.55.0",
"@opentelemetry/resources": "^2.2.0",
"@opentelemetry/resources": "^2.5.0",
"@opentelemetry/sdk-logs": "^0.211.0",
"@opentelemetry/sdk-metrics": "^2.2.0",
"@opentelemetry/sdk-metrics": "^2.5.0",
"@opentelemetry/sdk-node": "^0.211.0",
"@opentelemetry/sdk-trace-base": "^2.2.0",
"@opentelemetry/sdk-trace-node": "^2.2.0",
"@opentelemetry/sdk-trace-base": "^2.5.0",
"@opentelemetry/sdk-trace-node": "^2.5.0",
"@opentelemetry/semantic-conventions": "^1.39.0",
"cors": "^2.8.6",
"express": "^5.0.1",
"winston": "^3.18.3",
"zod": "^4.3.6"
},
"devDependencies": {
"@ai-sdk/azure": "^3.0.27",
"@ai-sdk/azure": "^3.0.28",
"@azure/identity": "^4.13.0",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/node": "^25.2.3",
"ai": "^6.0.79",
"ai": "^6.0.81",
Comment on lines +45 to +63
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description lists incorrect dependency version updates. The description claims updates to @opentelemetry/api (1.9.0 → 2.0.0), @opentelemetry/sdk-node (0.57.2 → 0.200.0), @opentelemetry/auto-instrumentations-node (0.57.2 → 0.200.0), @ai-sdk/azure (1.3.22 → 2.0.6), and ai (4.3.15 → 4.3.16).

However, the actual changes are:

  • @opentelemetry/resources: ^2.2.0 → ^2.5.0
  • @opentelemetry/sdk-metrics: ^2.2.0 → ^2.5.0
  • @opentelemetry/sdk-trace-base: ^2.2.0 → ^2.5.0
  • @opentelemetry/sdk-trace-node: ^2.2.0 → ^2.5.0
  • @ai-sdk/azure: ^3.0.27 → ^3.0.28
  • ai: ^6.0.79 → ^6.0.81

The PR description should be updated to reflect the actual dependency changes made.

Copilot uses AI. Check for mistakes.
"dotenv": "^17.2.4",
"typescript": "^5.7.2",
"vitest": "^4.0.18"
Expand Down
36 changes: 34 additions & 2 deletions src/datasources/local-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,38 @@ export class LocalRepositoryDataSource implements IAdvisoryDataSource {
};
}

/**
* Parse date filter string and return start/end dates
* Supports: "2026-01-27" (single day) or "2026-01-01..2026-01-31" (range)
*/
private parseDateFilter(dateStr: string): { start: string; end: string } {
// Defense-in-depth: ensure dateStr is a string (HTTP query params can be arrays)
const str = Array.isArray(dateStr) ? String(dateStr[0]) : String(dateStr);
if (str.includes('..')) {
const [start, end] = str.split('..');
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The split operation on line 312 doesn't limit the number of parts, so a malformed input like "2026-01-01..2026-02-01..2026-03-01" would silently use only the first two parts without warning the user. This could lead to confusion when debugging unexpected filter behavior.

Consider using split('..', 2) to limit the split to 2 parts, and then validate that exactly 2 parts were returned. If more than 2 parts exist, throw a descriptive error indicating the correct format.

Suggested change
const [start, end] = str.split('..');
const parts = str.split('..');
if (parts.length !== 2 || !parts[0] || !parts[1]) {
throw new Error('Invalid date range format. Expected "YYYY-MM-DD..YYYY-MM-DD".');
}
const [start, end] = parts;

Copilot uses AI. Check for mistakes.
// End date: include full day by using next day midnight
const endDate = new Date(end + 'T00:00:00Z');
endDate.setUTCDate(endDate.getUTCDate() + 1);
return { start: start + 'T00:00:00Z', end: endDate.toISOString() };
Comment on lines +312 to +316
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parseDateFilter method doesn't validate that the start date comes before the end date in a range filter. If a user provides "2026-12-31..2026-01-01", the filter will produce an empty result set without any error message, which could confuse users.

Add validation to ensure start is less than or equal to end when parsing a date range, and throw a descriptive error if the range is invalid.

Suggested change
const [start, end] = str.split('..');
// End date: include full day by using next day midnight
const endDate = new Date(end + 'T00:00:00Z');
endDate.setUTCDate(endDate.getUTCDate() + 1);
return { start: start + 'T00:00:00Z', end: endDate.toISOString() };
const [startRaw, endRaw] = str.split('..');
const startDate = new Date(startRaw + 'T00:00:00Z');
const endDate = new Date(endRaw + 'T00:00:00Z');
if (startDate > endDate) {
throw new Error(
`Invalid date range "${str}": start date must be less than or equal to end date.`,
);
}
// End date: include full day by using next day midnight (end is exclusive)
endDate.setUTCDate(endDate.getUTCDate() + 1);
return { start: startDate.toISOString(), end: endDate.toISOString() };

Copilot uses AI. Check for mistakes.
}
// Single date: filter for that specific day
const startDate = new Date(str + 'T00:00:00Z');
const endDate = new Date(str + 'T00:00:00Z');
Comment on lines +313 to +320
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parseDateFilter method lacks input validation for invalid dates. When an invalid date string is provided (e.g., "2026-13-45", "invalid-date", or "2026-02-30"), new Date() will create an Invalid Date object. The code will still proceed and call toISOString() on this Invalid Date, which will throw an error at runtime.

Add validation to check if the parsed dates are valid before proceeding. For example, after creating a Date object, check if date.getTime() returns NaN to detect invalid dates, and throw a descriptive error message.

Suggested change
// End date: include full day by using next day midnight
const endDate = new Date(end + 'T00:00:00Z');
endDate.setUTCDate(endDate.getUTCDate() + 1);
return { start: start + 'T00:00:00Z', end: endDate.toISOString() };
}
// Single date: filter for that specific day
const startDate = new Date(str + 'T00:00:00Z');
const endDate = new Date(str + 'T00:00:00Z');
// Validate start and end dates
const startDate = new Date(start + 'T00:00:00Z');
const endDate = new Date(end + 'T00:00:00Z');
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
throw new Error(`Invalid date filter: "${str}"`);
}
// End date: include full day by using next day midnight
endDate.setUTCDate(endDate.getUTCDate() + 1);
// Preserve original behavior for the start bound string
return { start: start + 'T00:00:00Z', end: endDate.toISOString() };
}
// Single date: filter for that specific day
const startDate = new Date(str + 'T00:00:00Z');
const endDate = new Date(str + 'T00:00:00Z');
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
throw new Error(`Invalid date filter: "${str}"`);
}

Copilot uses AI. Check for mistakes.
endDate.setUTCDate(endDate.getUTCDate() + 1);
return { start: startDate.toISOString(), end: endDate.toISOString() };
}

/**
* Filter advisories by date range
*/
private filterByDateRange(advisories: Advisory[], field: 'published_at' | 'updated_at', dateStr: string): Advisory[] {
const { start, end } = this.parseDateFilter(dateStr);
return advisories.filter(a => {
const date = a[field];
return date >= start && date < end;
});
}
Comment on lines +304 to +334
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new parseDateFilter and filterByDateRange methods lack unit test coverage. While there are E2E tests that exercise these methods indirectly, there are no unit tests that validate edge cases such as invalid dates, reversed date ranges, malformed input, or boundary conditions.

Consider adding unit tests for the LocalRepositoryDataSource class to cover these critical date parsing scenarios, following the pattern established in test/unit/refresh-database.test.ts.

Copilot uses AI. Check for mistakes.

/**
* List advisories with optional filtering
*/
Expand Down Expand Up @@ -349,11 +381,11 @@ export class LocalRepositoryDataSource implements IAdvisoryDataSource {
}

if (options.published) {
results = results.filter(a => a.published_at >= options.published!);
results = this.filterByDateRange(results, 'published_at', options.published);
}

if (options.updated) {
results = results.filter(a => a.updated_at >= options.updated!);
results = this.filterByDateRange(results, 'updated_at', options.updated);
}

// Sort results
Expand Down
Loading
Loading