diff --git a/app/config/openapi.js b/app/config/openapi.js index 9dbc7f5..4aa4099 100644 --- a/app/config/openapi.js +++ b/app/config/openapi.js @@ -428,10 +428,25 @@ const spec = { title: 'TimeTrackerAPI', version: pkg.version || '1.0.0', description: - 'Open-source Node.js + PostgreSQL TimeTrackerAPI. Customer and ' + - 'time-entry records, scoped by company via an `authKey` header. ' + + 'Open-source Node.js + PostgreSQL TimeTrackerAPI. 16 ' + + 'company-scoped entities (Customer, TimeEntry, Worker, ' + + 'BillingType, InventoryItem, Company, Job, Invoice, ' + + 'CustomerPayment, InvoiceJob, ProductEntry, VersionInfo, ' + + 'PurchaseOrderVendor, PurchaseOrderHeader, ' + + 'PurchaseOrderLine, InventoryTransaction), Stripe-style ' + + 'idempotency on every POST, RFC 5988 Link-header ' + + 'pagination, Prometheus `/metrics`, CSV export with OWASP ' + + 'formula-injection mitigation. Auth via `authKey` header. ' + 'Source: https://github.com/CryptoJones/TimeTrackerAPI / ' + 'https://codeberg.org/CryptoJones/TimeTrackerAPI.', + // Security-vulnerability reports route through the + // private channels in SECURITY.md — link surfaces in + // Swagger UI's info panel so docs consumers can find the + // policy without leaving the spec. + contact: { + name: 'Security policy (private vuln reports)', + url: 'https://github.com/CryptoJones/TimeTrackerAPI/security/policy', + }, license: { name: 'Apache 2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0', diff --git a/tests/api/openapi.test.js b/tests/api/openapi.test.js index 11146fc..819d44d 100644 --- a/tests/api/openapi.test.js +++ b/tests/api/openapi.test.js @@ -37,6 +37,16 @@ describe('OpenAPI spec', () => { expect(res.body.openapi).toMatch(/^3\./); expect(res.body.info.title).toBe('TimeTrackerAPI'); expect(res.body.info.version).toBeDefined(); + // license is required for downstream Apache-2.0 compliance + // tooling (e.g. SBOM scanners). Pin its presence and SPDX + // identifier so a future re-write can't silently drop it. + expect(res.body.info.license).toBeDefined(); + expect(res.body.info.license.name).toBe('Apache 2.0'); + // contact.url surfaces the security policy in Swagger UI's + // info panel — operators reading the docs find the + // vuln-report channel without leaving the spec page. + expect(res.body.info.contact).toBeDefined(); + expect(res.body.info.contact.url).toMatch(/security/i); }); test('spec includes all v1 paths', async () => {