Skip to content

Commit ad536a8

Browse files
committed
Add support for localhost development
1 parent da32c65 commit ad536a8

10 files changed

+49
-142
lines changed

src/portal-options/auth-config-provider.spec.ts

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { PMAuthConfigProvider } from './auth-config-provider.js';
2-
import { getDomainAndOrganization } from './utils/domain.js';
32
import { HttpException } from '@nestjs/common';
43
import {
54
DiscoveryService,
@@ -102,34 +101,4 @@ describe('PMAuthConfigProvider', () => {
102101

103102
await expect(provider.getAuthConfig(req)).rejects.toThrow(HttpException);
104103
});
105-
106-
it('getDomain should return organization and baseDomain', () => {
107-
const req = { hostname: 'foo.example.com' } as Request;
108-
const result = getDomainAndOrganization(req);
109-
expect(result).toEqual({
110-
organization: 'foo',
111-
baseDomain: 'example.com',
112-
});
113-
});
114-
115-
it('getDomain should return clientId if hostname equals baseDomain', () => {
116-
const req = { hostname: 'example.com' } as Request;
117-
const result = getDomainAndOrganization(req);
118-
expect(result).toEqual({
119-
organization: 'client123',
120-
baseDomain: 'example.com',
121-
});
122-
});
123-
124-
it('getDomain should return defaults for local developmentn', () => {
125-
const req = { hostname: 'localhost' } as Request;
126-
mockEnvService.getEnv.mockReturnValue({ isLocal: true });
127-
128-
const result = provider.getDomain(req);
129-
130-
expect(result).toEqual({
131-
organization: 'openmfp',
132-
baseDomain: 'localhost',
133-
});
134-
});
135104
});

src/portal-options/auth-config-provider.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getOrganization } from './utils/domain.js';
12
import { CoreV1Api, KubeConfig } from '@kubernetes/client-node';
23
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
34
import {
@@ -19,13 +20,7 @@ export class PMAuthConfigProvider implements AuthConfigService {
1920

2021
async getAuthConfig(request: Request): Promise<ServerAuthVariables> {
2122
const baseDomain = process.env['BASE_DOMAINS_DEFAULT'];
22-
23-
const subDomain = request.hostname.split('.')[0];
24-
const isSubdomain = request.hostname !== baseDomain;
25-
26-
const clientId = isSubdomain
27-
? subDomain
28-
: process.env['OIDC_CLIENT_ID_DEFAULT'];
23+
const clientId = getOrganization(request);
2924
const clientSecret = await this.getClientSecret(clientId);
3025

3126
const oidcUrl = process.env[`DISCOVERY_ENDPOINT`]?.replace(

src/portal-options/pm-portal-context.service.spec.ts

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { PMPortalContextService } from './pm-portal-context.service.js';
22
import { KcpKubernetesService } from './services/kcp-k8s.service.js';
3-
import { getDomainAndOrganization } from './utils/domain.js';
3+
import { getOrganization } from './utils/domain.js';
44
import { Test, TestingModule } from '@nestjs/testing';
55
import { Request } from 'express';
66
import { mock } from 'jest-mock-extended';
7+
import process from 'node:process';
78

89
jest.mock('@kubernetes/client-node', () => {
910
class KubeConfig {
@@ -23,22 +24,19 @@ jest.mock('@kubernetes/client-node', () => {
2324
});
2425

2526
jest.mock('./utils/domain.js', () => ({
26-
getDomainAndOrganization: jest.fn(),
27+
getOrganization: jest.fn(),
2728
}));
2829

2930
describe('PMPortalContextService', () => {
3031
let service: PMPortalContextService;
3132
let kcpKubernetesServiceMock: jest.Mocked<KcpKubernetesService>;
32-
const mockedGetDomainAndOrganization = jest.mocked(getDomainAndOrganization);
33+
const mockedGetDomainAndOrganization = jest.mocked(getOrganization);
3334
let mockRequest: any;
3435

3536
beforeEach(async () => {
3637
kcpKubernetesServiceMock = mock();
3738

38-
mockedGetDomainAndOrganization.mockReturnValue({
39-
baseDomain: 'example.com',
40-
organization: 'test-org',
41-
});
39+
mockedGetDomainAndOrganization.mockReturnValue('test-org');
4240

4341
const module: TestingModule = await Test.createTestingModule({
4442
providers: [
@@ -87,10 +85,7 @@ describe('PMPortalContextService', () => {
8785
process.env.OTHER_ENV_VAR = 'should-be-ignored';
8886

8987
try {
90-
mockedGetDomainAndOrganization.mockReturnValue({
91-
baseDomain: 'example.com',
92-
organization: 'test-org',
93-
});
88+
mockedGetDomainAndOrganization.mockReturnValue('test-org');
9489

9590
const result = await service.getContextValues(mockRequest as Request);
9691

@@ -110,10 +105,7 @@ describe('PMPortalContextService', () => {
110105
process.env.OPENMFP_PORTAL_CONTEXT_MULTIPLE_SNAKE_CASE_KEYS = 'value2';
111106

112107
try {
113-
mockedGetDomainAndOrganization.mockReturnValue({
114-
baseDomain: 'example.com',
115-
organization: 'test-org',
116-
});
108+
mockedGetDomainAndOrganization.mockReturnValue('test-org');
117109

118110
const result = await service.getContextValues(mockRequest as Request);
119111

@@ -132,10 +124,7 @@ describe('PMPortalContextService', () => {
132124
'https://${org-subdomain}api.example.com/${org-name}/graphql';
133125

134126
try {
135-
mockedGetDomainAndOrganization.mockReturnValue({
136-
baseDomain: 'example.com',
137-
organization: 'test-org',
138-
});
127+
mockedGetDomainAndOrganization.mockReturnValue('test-org');
139128

140129
mockRequest.hostname = 'subdomain.example.com';
141130

@@ -154,11 +143,8 @@ describe('PMPortalContextService', () => {
154143
'https://${org-subdomain}api.example.com/${org-name}/graphql';
155144

156145
try {
157-
mockedGetDomainAndOrganization.mockReturnValue({
158-
baseDomain: 'example.com',
159-
organization: 'test-org',
160-
});
161-
146+
mockedGetDomainAndOrganization.mockReturnValue('test-org');
147+
process.env['BASE_DOMAINS_DEFAULT'] = 'example.com';
162148
mockRequest.hostname = 'example.com';
163149

164150
const result = await service.getContextValues(mockRequest as Request);
@@ -177,10 +163,7 @@ describe('PMPortalContextService', () => {
177163
process.env.OPENMFP_PORTAL_CONTEXT_VALID_KEY = 'valid-value';
178164

179165
try {
180-
mockedGetDomainAndOrganization.mockReturnValue({
181-
baseDomain: 'example.com',
182-
organization: 'test-org',
183-
});
166+
mockedGetDomainAndOrganization.mockReturnValue('test-org');
184167

185168
const result = await service.getContextValues(mockRequest as Request);
186169

src/portal-options/pm-portal-context.service.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { KcpKubernetesService } from './services/kcp-k8s.service.js';
2-
import { getDomainAndOrganization } from './utils/domain.js';
2+
import { getOrganization } from './utils/domain.js';
33
import { Injectable } from '@nestjs/common';
44
import { PortalContextProvider } from '@openmfp/portal-server-lib';
55
import type { Request } from 'express';
@@ -31,7 +31,7 @@ export class PMPortalContextService implements PortalContextProvider {
3131
}
3232

3333
private addKcpWorkspaceUrl(request, portalContext) {
34-
const { organization } = getDomainAndOrganization(request);
34+
const organization = getOrganization(request);
3535
const account = request.query?.['core_platform-mesh_io_account'];
3636

3737
portalContext.kcpWorkspaceUrl = this.kcpKubernetesService
@@ -43,12 +43,12 @@ export class PMPortalContextService implements PortalContextProvider {
4343
request: Request,
4444
portalContext: Record<string, any>,
4545
): void {
46-
const org = getDomainAndOrganization(request);
47-
const subDomain =
48-
request.hostname === org.baseDomain ? '' : `${org.organization}.`;
46+
const org = getOrganization(request);
47+
const baseDomain = process.env['BASE_DOMAINS_DEFAULT'];
48+
const subDomain = request.hostname !== baseDomain ? `${org}.` : '';
4949
portalContext.crdGatewayApiUrl = portalContext.crdGatewayApiUrl
5050
?.replace('${org-subdomain}', subDomain)
51-
.replace('${org-name}', org.organization);
51+
.replace('${org-name}', org);
5252
}
5353

5454
private toCamelCase(text: string): string {

src/portal-options/pm-request-context-provider.spec.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PMPortalContextService } from './pm-portal-context.service.js';
22
import { PMRequestContextProvider } from './pm-request-context-provider.js';
3-
import { getDomainAndOrganization } from './utils/domain.js';
3+
import { getOrganization } from './utils/domain.js';
44
import type { Request } from 'express';
55
import { mock } from 'jest-mock-extended';
66

@@ -22,20 +22,17 @@ jest.mock('@kubernetes/client-node', () => {
2222
});
2323

2424
jest.mock('./utils/domain.js', () => ({
25-
getDomainAndOrganization: jest.fn(),
25+
getOrganization: jest.fn(),
2626
}));
2727

2828
describe('PMRequestContextProvider', () => {
2929
let provider: PMRequestContextProvider;
3030
const portalContextService = mock<PMPortalContextService>();
31-
const mockedGetDomainAndOrganization = jest.mocked(getDomainAndOrganization);
31+
const mockedGetOrganization = jest.mocked(getOrganization);
3232

3333
beforeEach(() => {
3434
jest.resetAllMocks();
35-
mockedGetDomainAndOrganization.mockReturnValue({
36-
organization: 'org1',
37-
baseDomain: 'org1.example.com',
38-
});
35+
mockedGetOrganization.mockReturnValue('org1');
3936
(
4037
portalContextService.getContextValues as unknown as jest.Mock
4138
).mockResolvedValue({
@@ -62,7 +59,7 @@ describe('PMRequestContextProvider', () => {
6259
organization: 'org1',
6360
});
6461

65-
expect(mockedGetDomainAndOrganization).toHaveBeenCalledWith(req);
62+
expect(mockedGetOrganization).toHaveBeenCalledWith(req);
6663
expect(portalContextService.getContextValues).toHaveBeenCalledWith(req);
6764
});
6865
});

src/portal-options/pm-request-context-provider.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { PMPortalContextService } from './pm-portal-context.service.js';
2-
import { getDomainAndOrganization } from './utils/domain.js';
2+
import { getOrganization } from './utils/domain.js';
33
import { Injectable } from '@nestjs/common';
44
import { RequestContextProvider } from '@openmfp/portal-server-lib';
55
import type { Request } from 'express';
@@ -16,12 +16,15 @@ export class PMRequestContextProvider implements RequestContextProvider {
1616
constructor(private pmPortalContextService: PMPortalContextService) {}
1717

1818
async getContextValues(request: Request): Promise<RequestContext> {
19-
const domainData = getDomainAndOrganization(request);
19+
const organization = getOrganization(request);
20+
const baseDomain = process.env['BASE_DOMAINS_DEFAULT'];
2021
return {
2122
...request.query,
2223
...(await this.pmPortalContextService.getContextValues(request)),
23-
organization: domainData.organization,
24-
isSubDomain: request.hostname !== domainData.baseDomain,
24+
organization,
25+
isSubDomain:
26+
request.hostname.includes('localhost') ||
27+
request.hostname !== baseDomain,
2528
};
2629
}
2730
}

src/portal-options/service-providers/content-configuration-service-providers.service.spec.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { RequestContext } from '../pm-request-context-provider.js';
22
import { ContentConfigurationServiceProvidersService } from './content-configuration-service-providers.service.js';
33
import { welcomeNodeConfig } from './models/welcome-node-config.js';
4-
import { EnvService } from '@openmfp/portal-server-lib';
54
import { GraphQLClient } from 'graphql-request';
6-
import { mock } from 'jest-mock-extended';
75

86
jest.mock('graphql-request', () => {
97
return {
@@ -19,13 +17,10 @@ jest.mock('graphql-request', () => {
1917
describe('ContentConfigurationServiceProvidersService', () => {
2018
let service: ContentConfigurationServiceProvidersService;
2119
let mockClient: jest.Mocked<GraphQLClient>;
22-
let mockEnvService: jest.Mocked<EnvService>;
2320
let context: RequestContext;
2421

2522
beforeEach(() => {
26-
mockEnvService = mock();
27-
mockEnvService.getEnv.mockReturnValue({ isLocal: false });
28-
service = new ContentConfigurationServiceProvidersService(mockEnvService);
23+
service = new ContentConfigurationServiceProvidersService();
2924
mockClient = new GraphQLClient('') as any;
3025
(GraphQLClient as jest.Mock).mockReturnValue(mockClient);
3126
context = {

src/portal-options/service-providers/content-configuration-service-providers.service.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { welcomeNodeConfig } from './models/welcome-node-config.js';
55
import { Injectable } from '@nestjs/common';
66
import {
77
ContentConfiguration,
8-
EnvService,
98
ServiceProviderResponse,
109
ServiceProviderService,
1110
} from '@openmfp/portal-server-lib';
@@ -15,8 +14,6 @@ import { GraphQLClient } from 'graphql-request';
1514
export class ContentConfigurationServiceProvidersService
1615
implements ServiceProviderService
1716
{
18-
constructor(private envService: EnvService) {}
19-
2017
async getServiceProviders(
2118
token: string,
2219
entities: string[],
@@ -27,8 +24,7 @@ export class ContentConfigurationServiceProvidersService
2724
throw new Error('Token is required');
2825
}
2926

30-
const { isLocal } = this.envService.getEnv();
31-
if (!context.isSubDomain && !isLocal) {
27+
if (!context.isSubDomain) {
3228
return welcomeNodeConfig;
3329
}
3430

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { getDomainAndOrganization } from './domain.js';
1+
import { getOrganization } from './domain.js';
22
import type { Request } from 'express';
33

4-
describe('getDomainAndOrganization', () => {
4+
describe('getOrganization', () => {
55
const OLD_ENV = process.env;
66

77
beforeEach(() => {
@@ -18,56 +18,30 @@ describe('getDomainAndOrganization', () => {
1818
const makeReq = (hostname: string): Request =>
1919
({ hostname }) as unknown as Request;
2020

21-
it('returns subdomain as organization when hostname is not base domain', () => {
22-
const req = makeReq('test-org.example.com');
23-
const result = getDomainAndOrganization(req);
24-
expect(result).toEqual({
25-
organization: 'test-org',
26-
baseDomain: 'example.com',
27-
});
21+
it('returns subdomain when hostname is not base domain', () => {
22+
const req = makeReq('team1.example.com');
23+
expect(getOrganization(req)).toBe('team1');
2824
});
2925

30-
it('returns client id as organization when hostname equals base domain', () => {
26+
it('returns client id when hostname equals base domain', () => {
3127
const req = makeReq('example.com');
32-
const result = getDomainAndOrganization(req);
33-
expect(result).toEqual({
34-
organization: 'default-client',
35-
baseDomain: 'example.com',
36-
});
28+
expect(getOrganization(req)).toBe('default-client');
3729
});
3830

39-
it('handles single-label hostnames', () => {
31+
it('handles single-label hostname', () => {
4032
const req = makeReq('localhost');
41-
const result = getDomainAndOrganization(req);
42-
expect(result).toEqual({
43-
organization: 'localhost',
44-
baseDomain: 'example.com',
45-
});
33+
expect(getOrganization(req)).toBe('localhost');
4634
});
4735

48-
it('handles multi-level subdomains', () => {
36+
it('handles multi-level subdomain', () => {
4937
const req = makeReq('alpha.beta.example.com');
50-
const result = getDomainAndOrganization(req);
51-
expect(result).toEqual({
52-
organization: 'alpha',
53-
baseDomain: 'example.com',
54-
});
38+
expect(getOrganization(req)).toBe('alpha');
5539
});
5640

57-
it('propagates updated env values', () => {
41+
it('reflects updated env values', () => {
5842
process.env.OIDC_CLIENT_ID_DEFAULT = 'another-client';
5943
process.env.BASE_DOMAINS_DEFAULT = 'corp.example.org';
60-
const req1 = makeReq('corp.example.org');
61-
const req2 = makeReq('dev.corp.example.org');
62-
63-
expect(getDomainAndOrganization(req1)).toEqual({
64-
organization: 'another-client',
65-
baseDomain: 'corp.example.org',
66-
});
67-
68-
expect(getDomainAndOrganization(req2)).toEqual({
69-
organization: 'dev',
70-
baseDomain: 'corp.example.org',
71-
});
44+
expect(getOrganization(makeReq('corp.example.org'))).toBe('another-client');
45+
expect(getOrganization(makeReq('dev.corp.example.org'))).toBe('dev');
7246
});
7347
});

0 commit comments

Comments
 (0)