diff --git a/workspaces/dcm/.changeset/rename-dcm-api-url.md b/workspaces/dcm/.changeset/rename-dcm-api-url.md new file mode 100644 index 0000000000..a5ca02bc28 --- /dev/null +++ b/workspaces/dcm/.changeset/rename-dcm-api-url.md @@ -0,0 +1,6 @@ +--- +'@red-hat-developer-hub/backstage-plugin-dcm-backend': patch +--- + +Rename DCM_API_GATEWAY_URL to DCM_API_URL. Legacy env var and +dcm.apiGatewayUrl config remain supported during migration. diff --git a/workspaces/dcm/app-config.production.yaml b/workspaces/dcm/app-config.production.yaml index 829b840553..2f459cda71 100644 --- a/workspaces/dcm/app-config.production.yaml +++ b/workspaces/dcm/app-config.production.yaml @@ -11,6 +11,8 @@ backend: connection: ':memory:' dcm: + apiUrl: ${DCM_API_URL:-} + # Legacy env var; kept until deploy configs switch to DCM_API_URL. apiGatewayUrl: ${DCM_API_GATEWAY_URL:-} ssoBaseUrl: ${DCM_SSO_BASE_URL:-} clientId: ${DCM_CLIENT_ID:-} diff --git a/workspaces/dcm/app-config.yaml b/workspaces/dcm/app-config.yaml index cbd5f40bab..9959b8d0ef 100644 --- a/workspaces/dcm/app-config.yaml +++ b/workspaces/dcm/app-config.yaml @@ -65,10 +65,10 @@ dcm: - security-baseline - compliance-pci - audit-logging - # Base URL of the DCM API Gateway. All three API services (catalog, + # Base URL of the DCM control plane. All three API services (catalog, # policy-manager, providers) are routed through this single endpoint. # Override in app-config.local.yaml for local development. - # apiGatewayUrl: https://your-api-gateway.example.com + # apiUrl: https://your-control-plane.example.com # # SSO credentials for the backend to obtain a bearer token: # ssoBaseUrl: https://sso.redhat.com diff --git a/workspaces/dcm/plugins/dcm-backend/app-config.dynamic.yaml b/workspaces/dcm/plugins/dcm-backend/app-config.dynamic.yaml index 7772490679..c22a5d07be 100644 --- a/workspaces/dcm/plugins/dcm-backend/app-config.dynamic.yaml +++ b/workspaces/dcm/plugins/dcm-backend/app-config.dynamic.yaml @@ -1,5 +1,7 @@ dcm: - # Base URL of the DCM API Gateway (required). + # Base URL of the DCM control plane (required). + apiUrl: ${DCM_API_URL} + # Legacy env var; kept until deploy configs switch to DCM_API_URL. apiGatewayUrl: ${DCM_API_GATEWAY_URL} # SSO configuration for the backend to obtain bearer tokens via diff --git a/workspaces/dcm/plugins/dcm-backend/config.d.ts b/workspaces/dcm/plugins/dcm-backend/config.d.ts index 441078f62e..78259ce87f 100644 --- a/workspaces/dcm/plugins/dcm-backend/config.d.ts +++ b/workspaces/dcm/plugins/dcm-backend/config.d.ts @@ -17,13 +17,24 @@ export interface Config { dcm: { /** - * Base URL of the DCM API Gateway. + * Base URL of the DCM control plane. * * All API services (catalog, policy-manager, providers) are routed - * through this single gateway. The backend appends `/api/v1alpha1/` + * through this endpoint. The backend appends `/api/v1alpha1/` * to construct the upstream URL. * - * @example "http://localhost:9080" + * @example "http://localhost:8080" + * @visibility backend + */ + apiUrl?: string; + + /** + * Base URL of the DCM API Gateway. + * + * @deprecated Use `apiUrl` instead. This key remains supported for + * backward compatibility during migration. + * + * @example "http://localhost:9080" (legacy API gateway port) * @visibility backend */ apiGatewayUrl?: string; diff --git a/workspaces/dcm/plugins/dcm-backend/src/routes/proxy.test.ts b/workspaces/dcm/plugins/dcm-backend/src/routes/proxy.test.ts index 3a57201593..b00e48af42 100644 --- a/workspaces/dcm/plugins/dcm-backend/src/routes/proxy.test.ts +++ b/workspaces/dcm/plugins/dcm-backend/src/routes/proxy.test.ts @@ -59,7 +59,7 @@ describe('createDcmProxy', () => { fetchSpy?.mockRestore(); }); - it('returns 503 when dcm.apiGatewayUrl is not configured', async () => { + it('returns 503 when dcm.apiUrl is not configured', async () => { const app = makeApp({ dcm: { clientId: 'id', clientSecret: 'secret' } }); const res = await request(app).get('/proxy/providers'); @@ -77,7 +77,7 @@ describe('createDcmProxy', () => { const app = makeApp({ dcm: { - apiGatewayUrl: 'https://gateway.example.com', + apiUrl: 'https://control-plane.example.com', clientId: 'id', clientSecret: 'secret', }, @@ -101,7 +101,7 @@ describe('createDcmProxy', () => { const app = makeApp({ dcm: { - apiGatewayUrl: 'https://gateway.example.com', + apiUrl: 'https://control-plane.example.com', clientId: 'id', clientSecret: 'secret', }, @@ -111,7 +111,7 @@ describe('createDcmProxy', () => { expect(res.status).toBe(502); expect(res.body).toMatchObject({ - error: expect.stringContaining('DCM API gateway'), + error: expect.stringContaining('DCM API'), }); }); @@ -134,7 +134,7 @@ describe('createDcmProxy', () => { const app = makeApp({ dcm: { - apiGatewayUrl: 'https://gateway.example.com', + apiUrl: 'https://control-plane.example.com', clientId: 'id', clientSecret: 'secret', }, @@ -171,7 +171,7 @@ describe('createDcmProxy', () => { const app = makeApp({ dcm: { - apiGatewayUrl: 'https://gateway.example.com', + apiUrl: 'https://control-plane.example.com', clientId: 'id', clientSecret: 'secret', }, @@ -206,7 +206,7 @@ describe('createDcmProxy', () => { const app = makeApp({ dcm: { - apiGatewayUrl: 'https://gateway.example.com', + apiUrl: 'https://control-plane.example.com', clientId: 'id', clientSecret: 'secret', }, @@ -227,7 +227,7 @@ describe('createDcmProxy', () => { expect(JSON.parse(upstreamCall[1].body)).toEqual(patch); }); - it('handles 204 No Content upstream responses without a body', async () => { + it('falls back to legacy dcm.apiGatewayUrl and handles 204 No Content', async () => { fetchSpy = jest .spyOn(globalThis, 'fetch') .mockResolvedValueOnce(TOKEN_RESPONSE) diff --git a/workspaces/dcm/plugins/dcm-backend/src/routes/proxy.ts b/workspaces/dcm/plugins/dcm-backend/src/routes/proxy.ts index 76439079c6..d51ebe8b5e 100644 --- a/workspaces/dcm/plugins/dcm-backend/src/routes/proxy.ts +++ b/workspaces/dcm/plugins/dcm-backend/src/routes/proxy.ts @@ -21,10 +21,10 @@ import { getTokenFromApi } from '../util/tokenUtil'; const API_BASE_PATH = '/api/v1alpha1'; /** - * Proxies all `ALL /proxy/*` requests to the DCM API Gateway. + * Proxies all `ALL /proxy/*` requests to the DCM control plane. * * The wildcard path segment is appended to: - * `{dcm.apiGatewayUrl}/api/v1alpha1/` + * `{dcm.apiUrl}/api/v1alpha1/` * * An SSO bearer token is injected automatically via `tokenUtil`. */ @@ -32,24 +32,24 @@ export function createDcmProxy(options: RouterOptions) { return async (req: Request, res: Response): Promise => { const { logger, config } = options; - const apiGatewayUrl = config.getOptionalString('dcm.apiGatewayUrl'); - if (!apiGatewayUrl) { + // Prefer dcm.apiUrl (DCM_API_URL); legacy apiGatewayUrl eases migration. + const apiUrl = + config.getOptionalString('dcm.apiUrl') ?? + config.getOptionalString('dcm.apiGatewayUrl'); + if (!apiUrl) { logger.error( - 'dcm.apiGatewayUrl is not configured — cannot proxy DCM API requests.', + 'dcm.apiUrl is not configured — cannot proxy DCM API requests.', ); res .status(503) - .json({ error: 'DCM API gateway is not configured on the server.' }); + .json({ error: 'DCM API is not configured on the server.' }); return; } // req.params[0] is the captured wildcard after /proxy/ const wildcardPath = (req.params as Record)[0] ?? ''; - const targetUrl = new URL( - `${API_BASE_PATH}/${wildcardPath}`, - apiGatewayUrl, - ); + const targetUrl = new URL(`${API_BASE_PATH}/${wildcardPath}`, apiUrl); // Forward all query parameters from the original request const incomingParams = new URLSearchParams( @@ -80,7 +80,7 @@ export function createDcmProxy(options: RouterOptions) { // Only attach the Authorization header when an SSO token was obtained. // When clientId/clientSecret are not configured the token is empty and - // the request is forwarded without auth (open/unauthenticated gateway). + // the request is forwarded without auth (open/unauthenticated API). if (tokenResult.accessToken) { requestHeaders.Authorization = `Bearer ${tokenResult.accessToken}`; } @@ -104,7 +104,7 @@ export function createDcmProxy(options: RouterOptions) { }); } catch (err) { logger.error(`DCM proxy: upstream fetch failed — ${err}`); - res.status(502).json({ error: 'Failed to reach the DCM API gateway.' }); + res.status(502).json({ error: 'Failed to reach the DCM API.' }); return; } diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts b/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts index 6f7f651f6d..2bc2e3500b 100644 --- a/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts +++ b/workspaces/dcm/plugins/dcm-common/src/clients/CatalogClient.ts @@ -30,7 +30,7 @@ import { DcmBaseClient } from './DcmBaseClient'; * * All requests are sent to `/api/dcm/proxy/` where the backend * strips the `/proxy` prefix and forwards to: - * `{dcm.apiGatewayUrl}/api/v1alpha1/` + * `{dcm.apiUrl}/api/v1alpha1/` * * @public */ diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/DcmBaseClient.ts b/workspaces/dcm/plugins/dcm-common/src/clients/DcmBaseClient.ts index 08a3ccec13..88b4d3e6bd 100644 --- a/workspaces/dcm/plugins/dcm-common/src/clients/DcmBaseClient.ts +++ b/workspaces/dcm/plugins/dcm-common/src/clients/DcmBaseClient.ts @@ -23,7 +23,7 @@ const PLUGIN_ID = 'dcm'; * Base class shared by all DCM API clients. * * Routes every call through the dcm-backend secure proxy: - * `GET /api/dcm/proxy/` → `{dcm.apiGatewayUrl}/api/v1alpha1/` + * `GET /api/dcm/proxy/` → `{dcm.apiUrl}/api/v1alpha1/` * * @public */ diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/PolicyManagerClient.ts b/workspaces/dcm/plugins/dcm-common/src/clients/PolicyManagerClient.ts index 4f32282e80..ab1fa58c6f 100644 --- a/workspaces/dcm/plugins/dcm-common/src/clients/PolicyManagerClient.ts +++ b/workspaces/dcm/plugins/dcm-common/src/clients/PolicyManagerClient.ts @@ -23,7 +23,7 @@ import { DcmBaseClient } from './DcmBaseClient'; * * All requests are sent to `/api/dcm/proxy/` where the backend * strips the `/proxy` prefix and forwards to: - * `{dcm.apiGatewayUrl}/api/v1alpha1/` + * `{dcm.apiUrl}/api/v1alpha1/` * * @public */ diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/ProvidersClient.ts b/workspaces/dcm/plugins/dcm-common/src/clients/ProvidersClient.ts index 77155ae45a..8b26331ae7 100644 --- a/workspaces/dcm/plugins/dcm-common/src/clients/ProvidersClient.ts +++ b/workspaces/dcm/plugins/dcm-common/src/clients/ProvidersClient.ts @@ -23,7 +23,7 @@ import { DcmBaseClient } from './DcmBaseClient'; * * All requests are sent to `/api/dcm/proxy/` where the backend * strips the `/proxy` prefix and forwards to: - * `{dcm.apiGatewayUrl}/api/v1alpha1/` + * `{dcm.apiUrl}/api/v1alpha1/` * * @public */ diff --git a/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesClient.ts b/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesClient.ts index cb6becc0a2..85ea304549 100644 --- a/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesClient.ts +++ b/workspaces/dcm/plugins/dcm-common/src/clients/ResourcesClient.ts @@ -25,7 +25,7 @@ import type { * Default implementation of {@link ResourcesApi}. * * Routes calls through the dcm-backend secure proxy to the - * `/service-type-instances` endpoint of the DCM API Gateway. + * `/service-type-instances` endpoint of the DCM control plane. * * @public */