@red-hat-developer-hub/e2e-test-utils 2.1.11 → 2.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/deployment/keycloak/deployment.d.ts +28 -1
  2. package/dist/deployment/keycloak/deployment.d.ts.map +1 -1
  3. package/dist/deployment/keycloak/deployment.js +210 -0
  4. package/dist/deployment/keycloak/index.d.ts +2 -1
  5. package/dist/deployment/keycloak/index.d.ts.map +1 -1
  6. package/dist/deployment/keycloak/index.js +1 -0
  7. package/dist/deployment/keycloak/types.d.ts +35 -0
  8. package/dist/deployment/keycloak/types.d.ts.map +1 -1
  9. package/dist/deployment/openldap/config/seed.ldif +102 -0
  10. package/dist/deployment/openldap/constants.d.ts +46 -0
  11. package/dist/deployment/openldap/constants.d.ts.map +1 -0
  12. package/dist/deployment/openldap/constants.js +65 -0
  13. package/dist/deployment/openldap/deployment.d.ts +31 -0
  14. package/dist/deployment/openldap/deployment.d.ts.map +1 -0
  15. package/dist/deployment/openldap/deployment.js +219 -0
  16. package/dist/deployment/openldap/index.d.ts +4 -0
  17. package/dist/deployment/openldap/index.d.ts.map +1 -0
  18. package/dist/deployment/openldap/index.js +2 -0
  19. package/dist/deployment/openldap/types.d.ts +34 -0
  20. package/dist/deployment/openldap/types.d.ts.map +1 -0
  21. package/dist/deployment/openldap/types.js +1 -0
  22. package/dist/playwright/global-setup.d.ts +5 -0
  23. package/dist/playwright/global-setup.d.ts.map +1 -1
  24. package/dist/playwright/global-setup.js +2 -4
  25. package/dist/playwright/helpers/common.d.ts +73 -2
  26. package/dist/playwright/helpers/common.d.ts.map +1 -1
  27. package/dist/playwright/helpers/common.js +159 -39
  28. package/dist/playwright/helpers/github-session.test.d.ts +2 -0
  29. package/dist/playwright/helpers/github-session.test.d.ts.map +1 -0
  30. package/dist/playwright/helpers/github-session.test.js +199 -0
  31. package/dist/playwright/tests/global-setup.test.d.ts +2 -0
  32. package/dist/playwright/tests/global-setup.test.d.ts.map +1 -0
  33. package/dist/playwright/tests/global-setup.test.js +68 -0
  34. package/dist/secrets/bitwarden.d.ts +34 -0
  35. package/dist/secrets/bitwarden.d.ts.map +1 -0
  36. package/dist/secrets/bitwarden.js +193 -0
  37. package/dist/secrets/cli.d.ts +11 -0
  38. package/dist/secrets/cli.d.ts.map +1 -0
  39. package/dist/secrets/cli.js +98 -0
  40. package/dist/secrets/command.d.ts +15 -0
  41. package/dist/secrets/command.d.ts.map +1 -0
  42. package/dist/secrets/command.js +30 -0
  43. package/dist/secrets/config.d.ts +33 -0
  44. package/dist/secrets/config.d.ts.map +1 -0
  45. package/dist/secrets/config.js +156 -0
  46. package/dist/secrets/environment.d.ts +10 -0
  47. package/dist/secrets/environment.d.ts.map +1 -0
  48. package/dist/secrets/environment.js +53 -0
  49. package/dist/secrets/exec.d.ts +18 -0
  50. package/dist/secrets/exec.d.ts.map +1 -0
  51. package/dist/secrets/exec.js +50 -0
  52. package/dist/secrets/index.d.ts +5 -0
  53. package/dist/secrets/index.d.ts.map +1 -0
  54. package/dist/secrets/index.js +4 -0
  55. package/dist/secrets/tests/bitwarden.integration.test.d.ts +2 -0
  56. package/dist/secrets/tests/bitwarden.integration.test.d.ts.map +1 -0
  57. package/dist/secrets/tests/bitwarden.integration.test.js +50 -0
  58. package/dist/secrets/tests/bitwarden.test.d.ts +2 -0
  59. package/dist/secrets/tests/bitwarden.test.d.ts.map +1 -0
  60. package/dist/secrets/tests/bitwarden.test.js +418 -0
  61. package/dist/secrets/tests/cli.integration.test.d.ts +2 -0
  62. package/dist/secrets/tests/cli.integration.test.d.ts.map +1 -0
  63. package/dist/secrets/tests/cli.integration.test.js +70 -0
  64. package/dist/secrets/tests/cli.test.d.ts +2 -0
  65. package/dist/secrets/tests/cli.test.d.ts.map +1 -0
  66. package/dist/secrets/tests/cli.test.js +42 -0
  67. package/dist/secrets/tests/config.test.d.ts +2 -0
  68. package/dist/secrets/tests/config.test.d.ts.map +1 -0
  69. package/dist/secrets/tests/config.test.js +105 -0
  70. package/dist/secrets/tests/environment.test.d.ts +2 -0
  71. package/dist/secrets/tests/environment.test.d.ts.map +1 -0
  72. package/dist/secrets/tests/environment.test.js +119 -0
  73. package/dist/secrets/tests/exec.test.d.ts +2 -0
  74. package/dist/secrets/tests/exec.test.d.ts.map +1 -0
  75. package/dist/secrets/tests/exec.test.js +87 -0
  76. package/package.json +13 -2
  77. package/dist/utils/vault.d.ts +0 -16
  78. package/dist/utils/vault.d.ts.map +0 -1
  79. package/dist/utils/vault.js +0 -94
@@ -1,5 +1,5 @@
1
1
  import { KubernetesClientHelper } from "../../utils/kubernetes-client.js";
2
- import type { KeycloakDeploymentOptions, KeycloakDeploymentConfig, KeycloakClientConfig, KeycloakUserConfig, KeycloakGroupConfig, KeycloakRealmConfig, KeycloakConnectionConfig } from "./types.js";
2
+ import type { KeycloakDeploymentOptions, KeycloakDeploymentConfig, KeycloakClientConfig, KeycloakUserConfig, KeycloakGroupConfig, KeycloakRealmConfig, KeycloakConnectionConfig, KeycloakLdapFederationConfig, KeycloakLdapMapperConfig, KeycloakProtocolMapperConfig, KeycloakLdapRealmOptions } from "./types.js";
3
3
  export declare class KeycloakHelper {
4
4
  k8sClient: KubernetesClientHelper;
5
5
  deploymentConfig: KeycloakDeploymentConfig;
@@ -84,6 +84,32 @@ export declare class KeycloakHelper {
84
84
  * Delete a realm
85
85
  */
86
86
  deleteRealm(realm: string): Promise<void>;
87
+ /**
88
+ * Create (or return existing) LDAP user federation component on a realm.
89
+ * Requires admin credentials via connect()/deploy().
90
+ */
91
+ createLdapUserFederation(realm: string, config: KeycloakLdapFederationConfig): Promise<string>;
92
+ getLdapUserFederation(realm: string, name?: string): Promise<{
93
+ id: string;
94
+ name?: string;
95
+ } | undefined>;
96
+ updateLdapUserFederation(id: string, config: KeycloakLdapFederationConfig, realm: string): Promise<void>;
97
+ deleteLdapUserFederation(id: string, realm: string): Promise<void>;
98
+ createLdapMapper(realm: string, parentId: string, mapper: KeycloakLdapMapperConfig): Promise<string>;
99
+ listLdapMappers(realm: string, parentId: string): Promise<Array<{
100
+ id?: string;
101
+ name?: string;
102
+ }>>;
103
+ syncLdapUsers(federationId: string, action?: "triggerFullSync" | "triggerChangedUsersSync"): Promise<void>;
104
+ /**
105
+ * Add an OIDC protocol mapper on a client (e.g. ldap_uuid user attribute → claim).
106
+ */
107
+ addClientProtocolMapper(realm: string, clientId: string, mapper: KeycloakProtocolMapperConfig): Promise<void>;
108
+ /**
109
+ * One-shot: separate LDAP-fed realm + client + OpenLDAP federation + ldap_uuid claim.
110
+ * Connect as Keycloak admin first (username/password), not the RHDH service account.
111
+ */
112
+ configureLdapRealm(options: KeycloakLdapRealmOptions): Promise<void>;
87
113
  /**
88
114
  * Teardown Keycloak deployment
89
115
  */
@@ -101,6 +127,7 @@ export declare class KeycloakHelper {
101
127
  private _ensureAdminClient;
102
128
  private _assignServiceAccountRoles;
103
129
  private _addUserToGroup;
130
+ private _ldapFederationConfigToComponent;
104
131
  private _isConflictError;
105
132
  private _log;
106
133
  }
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../../src/deployment/keycloak/deployment.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../../src/deployment/keycloak/deployment.ts"],"names":[],"mappings":"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"}
@@ -333,6 +333,188 @@ export class KeycloakHelper {
333
333
  this._log(`Failed to delete realm ${realm}: ${error}`);
334
334
  }
335
335
  }
336
+ /**
337
+ * Create (or return existing) LDAP user federation component on a realm.
338
+ * Requires admin credentials via connect()/deploy().
339
+ */
340
+ async createLdapUserFederation(realm, config) {
341
+ await this._ensureAdminClient();
342
+ this._adminClient.setConfig({ realmName: realm });
343
+ const name = config.name ?? "openldap";
344
+ const existing = await this.getLdapUserFederation(realm, name);
345
+ if (existing?.id) {
346
+ this._log(`LDAP federation ${name} already exists (${existing.id})`);
347
+ await this.updateLdapUserFederation(existing.id, config, realm);
348
+ return existing.id;
349
+ }
350
+ const realmRep = await this._adminClient.realms.findOne({ realm });
351
+ if (!realmRep?.id) {
352
+ throw new Error(`Realm ${realm} not found`);
353
+ }
354
+ const { id } = await this._adminClient.components.create({
355
+ realm,
356
+ name,
357
+ providerId: "ldap",
358
+ providerType: "org.keycloak.storage.UserStorageProvider",
359
+ parentId: realmRep.id,
360
+ config: this._ldapFederationConfigToComponent(config),
361
+ });
362
+ this._log(`Created LDAP federation: ${name} (${id})`);
363
+ return id;
364
+ }
365
+ async getLdapUserFederation(realm, name) {
366
+ await this._ensureAdminClient();
367
+ this._adminClient.setConfig({ realmName: realm });
368
+ const components = await this._adminClient.components.find({
369
+ realm,
370
+ type: "org.keycloak.storage.UserStorageProvider",
371
+ });
372
+ const match = name
373
+ ? components.find((c) => c.name === name && c.providerId === "ldap")
374
+ : components.find((c) => c.providerId === "ldap");
375
+ return match?.id ? { id: match.id, name: match.name } : undefined;
376
+ }
377
+ async updateLdapUserFederation(id, config, realm) {
378
+ await this._ensureAdminClient();
379
+ this._adminClient.setConfig({ realmName: realm });
380
+ const current = await this._adminClient.components.findOne({ id, realm });
381
+ if (!current) {
382
+ throw new Error(`LDAP federation component ${id} not found`);
383
+ }
384
+ await this._adminClient.components.update({ id, realm }, {
385
+ ...current,
386
+ config: {
387
+ ...current.config,
388
+ ...this._ldapFederationConfigToComponent(config),
389
+ },
390
+ });
391
+ this._log(`Updated LDAP federation: ${id}`);
392
+ }
393
+ async deleteLdapUserFederation(id, realm) {
394
+ await this._ensureAdminClient();
395
+ await this._adminClient.components.del({ id, realm });
396
+ this._log(`Deleted LDAP federation: ${id}`);
397
+ }
398
+ async createLdapMapper(realm, parentId, mapper) {
399
+ await this._ensureAdminClient();
400
+ this._adminClient.setConfig({ realmName: realm });
401
+ const existing = await this.listLdapMappers(realm, parentId);
402
+ const found = existing.find((m) => m.name === mapper.name);
403
+ if (found?.id) {
404
+ this._log(`LDAP mapper ${mapper.name} already exists`);
405
+ return found.id;
406
+ }
407
+ const configEntries = {};
408
+ for (const [key, value] of Object.entries(mapper.config)) {
409
+ configEntries[key] = [value];
410
+ }
411
+ const { id } = await this._adminClient.components.create({
412
+ realm,
413
+ name: mapper.name,
414
+ parentId,
415
+ providerId: mapper.providerId,
416
+ providerType: "org.keycloak.storage.ldap.mappers.LDAPStorageMapper",
417
+ config: configEntries,
418
+ });
419
+ this._log(`Created LDAP mapper: ${mapper.name}`);
420
+ return id;
421
+ }
422
+ async listLdapMappers(realm, parentId) {
423
+ await this._ensureAdminClient();
424
+ return this._adminClient.components.find({
425
+ realm,
426
+ parent: parentId,
427
+ type: "org.keycloak.storage.ldap.mappers.LDAPStorageMapper",
428
+ });
429
+ }
430
+ async syncLdapUsers(federationId, action = "triggerFullSync") {
431
+ await this._ensureAdminClient();
432
+ await this._adminClient.userStorageProvider.sync({
433
+ id: federationId,
434
+ action,
435
+ });
436
+ this._log(`Triggered LDAP sync (${action}) for ${federationId}`);
437
+ }
438
+ /**
439
+ * Add an OIDC protocol mapper on a client (e.g. ldap_uuid user attribute → claim).
440
+ */
441
+ async addClientProtocolMapper(realm, clientId, mapper) {
442
+ await this._ensureAdminClient();
443
+ this._adminClient.setConfig({ realmName: realm });
444
+ const clients = await this._adminClient.clients.find({ clientId });
445
+ if (clients.length === 0 || !clients[0].id) {
446
+ throw new Error(`Client ${clientId} not found in realm ${realm}`);
447
+ }
448
+ const id = clients[0].id;
449
+ const existing = await this._adminClient.clients.listProtocolMappers({
450
+ id,
451
+ realm,
452
+ });
453
+ if (existing.some((m) => m.name === mapper.name)) {
454
+ this._log(`Protocol mapper ${mapper.name} already exists on ${clientId}`);
455
+ return;
456
+ }
457
+ await this._adminClient.clients.addProtocolMapper({ id, realm }, {
458
+ name: mapper.name,
459
+ protocol: mapper.protocol ?? "openid-connect",
460
+ protocolMapper: mapper.protocolMapper,
461
+ config: mapper.config,
462
+ });
463
+ this._log(`Added protocol mapper ${mapper.name} on client ${clientId}`);
464
+ }
465
+ /**
466
+ * One-shot: separate LDAP-fed realm + client + OpenLDAP federation + ldap_uuid claim.
467
+ * Connect as Keycloak admin first (username/password), not the RHDH service account.
468
+ */
469
+ async configureLdapRealm(options) {
470
+ await this._ensureAdminClient();
471
+ const realmName = options.realm;
472
+ await this.createRealm({ realm: realmName, enabled: true });
473
+ const clientConfig = {
474
+ ...DEFAULT_RHDH_CLIENT,
475
+ clientId: "rhdh-ldap-client",
476
+ clientSecret: "rhdh-ldap-client-secret",
477
+ name: "RHDH LDAP Client",
478
+ ...options.client,
479
+ };
480
+ await this.createClient(realmName, clientConfig);
481
+ await this._assignServiceAccountRoles(realmName, clientConfig.clientId);
482
+ const federationId = await this.createLdapUserFederation(realmName, options.ldap);
483
+ // Map LDAP entryUUID into a Keycloak user attribute for the token claim.
484
+ /* eslint-disable @typescript-eslint/naming-convention -- Keycloak Admin API mapper config keys */
485
+ const ldapUuidMapperConfig = {
486
+ "user.model.attribute": "ldap_uuid",
487
+ "ldap.attribute": options.ldap.uuidLdapAttribute ?? "entryUUID",
488
+ "read.only": "true",
489
+ "always.read.value.from.ldap": "true",
490
+ "is.binary.attribute": "false",
491
+ };
492
+ const claim = options.ldapUuidClaim ?? "ldap_uuid";
493
+ const ldapUuidClaimConfig = {
494
+ "user.attribute": "ldap_uuid",
495
+ "claim.name": claim,
496
+ "jsonType.label": "String",
497
+ "id.token.claim": "true",
498
+ "access.token.claim": "true",
499
+ "userinfo.token.claim": "true",
500
+ };
501
+ /* eslint-enable @typescript-eslint/naming-convention */
502
+ await this.createLdapMapper(realmName, federationId, {
503
+ name: "ldap-uuid",
504
+ providerId: "user-attribute-ldap-mapper",
505
+ config: ldapUuidMapperConfig,
506
+ });
507
+ await this.addClientProtocolMapper(realmName, clientConfig.clientId, {
508
+ name: "ldap-uuid-claim",
509
+ protocolMapper: "oidc-usermodel-attribute-mapper",
510
+ config: ldapUuidClaimConfig,
511
+ });
512
+ await this.syncLdapUsers(federationId);
513
+ this.realm = realmName;
514
+ this.clientId = clientConfig.clientId;
515
+ this.clientSecret = clientConfig.clientSecret;
516
+ this._log(`Configured LDAP realm ${realmName}`);
517
+ }
336
518
  /**
337
519
  * Teardown Keycloak deployment
338
520
  */
@@ -475,6 +657,34 @@ spec:
475
657
  this._log(` Warning: Group ${groupName} not found`);
476
658
  }
477
659
  }
660
+ _ldapFederationConfigToComponent(config) {
661
+ const bool = (v, fallback) => String(v ?? fallback);
662
+ return {
663
+ enabled: ["true"],
664
+ priority: ["0"],
665
+ vendor: [config.vendor ?? "other"],
666
+ connectionUrl: [config.connectionUrl],
667
+ bindDn: [config.bindDn],
668
+ bindCredential: [config.bindCredential],
669
+ usersDn: [config.usersDn],
670
+ usernameLDAPAttribute: [config.usernameLdapAttribute ?? "uid"],
671
+ rdnLDAPAttribute: [config.rdnLdapAttribute ?? "uid"],
672
+ uuidLDAPAttribute: [config.uuidLdapAttribute ?? "entryUUID"],
673
+ userObjectClasses: [
674
+ config.userObjectClasses ?? "inetOrgPerson, organizationalPerson",
675
+ ],
676
+ editMode: [config.editMode ?? "READ_ONLY"],
677
+ importEnabled: [bool(config.importEnabled, true)],
678
+ pagination: [bool(config.pagination, true)],
679
+ searchScope: [config.searchScope ?? "1"],
680
+ trustEmail: [bool(config.trustEmail, true)],
681
+ authType: ["simple"],
682
+ syncRegistrations: ["false"],
683
+ useTruststoreSpi: ["ldapsOnly"],
684
+ connectionPooling: ["true"],
685
+ cachePolicy: ["DEFAULT"],
686
+ };
687
+ }
478
688
  _isConflictError(error) {
479
689
  const err = error;
480
690
  return err.response?.status === 409 || err.status === 409;
@@ -1,3 +1,4 @@
1
1
  export { KeycloakHelper } from "./deployment.js";
2
- export type { KeycloakUserConfig, KeycloakGroupConfig } from "./types.js";
2
+ export { DEFAULT_GROUPS, DEFAULT_KEYCLOAK_CONFIG, DEFAULT_USERS, } from "./constants.js";
3
+ export type { KeycloakUserConfig, KeycloakGroupConfig, KeycloakLdapFederationConfig, KeycloakLdapRealmOptions, KeycloakClientConfig, } from "./types.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/deployment/keycloak/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/deployment/keycloak/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,cAAc,EACd,uBAAuB,EACvB,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,kBAAkB,EAClB,mBAAmB,EACnB,4BAA4B,EAC5B,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
@@ -1 +1,2 @@
1
1
  export { KeycloakHelper } from "./deployment.js";
2
+ export { DEFAULT_GROUPS, DEFAULT_KEYCLOAK_CONFIG, DEFAULT_USERS, } from "./constants.js";
@@ -56,4 +56,39 @@ export type KeycloakConnectionConfig = {
56
56
  username?: string;
57
57
  password?: string;
58
58
  };
59
+ export type KeycloakLdapFederationConfig = {
60
+ name?: string;
61
+ connectionUrl: string;
62
+ bindDn: string;
63
+ bindCredential: string;
64
+ usersDn: string;
65
+ usernameLdapAttribute?: string;
66
+ rdnLdapAttribute?: string;
67
+ uuidLdapAttribute?: string;
68
+ userObjectClasses?: string;
69
+ vendor?: string;
70
+ editMode?: string;
71
+ importEnabled?: boolean;
72
+ pagination?: boolean;
73
+ searchScope?: string;
74
+ trustEmail?: boolean;
75
+ };
76
+ export type KeycloakLdapMapperConfig = {
77
+ name: string;
78
+ providerId: string;
79
+ config: Record<string, string>;
80
+ };
81
+ export type KeycloakProtocolMapperConfig = {
82
+ name: string;
83
+ protocol?: string;
84
+ protocolMapper: string;
85
+ config: Record<string, string>;
86
+ };
87
+ export type KeycloakLdapRealmOptions = {
88
+ realm: string;
89
+ client?: Partial<KeycloakClientConfig>;
90
+ ldap: KeycloakLdapFederationConfig;
91
+ /** Protocol mapper claim name for LDAP UUID (default ldap_uuid). */
92
+ ldapUuidClaim?: string;
93
+ };
59
94
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/deployment/keycloak/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/deployment/keycloak/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ # Bootstrap tree for RHDH LDAP e2e (OpenLDAP / Bitnami).
2
+ # Loaded via LDAP_CUSTOM_LDIF_DIR=/ldifs — must include root + OUs.
3
+
4
+ dn: dc=rhdh,dc=test
5
+ objectClass: dcObject
6
+ objectClass: organization
7
+ o: RHDH Test
8
+ dc: rhdh
9
+
10
+ dn: ou=users,dc=rhdh,dc=test
11
+ objectClass: organizationalUnit
12
+ ou: users
13
+
14
+ dn: ou=groups,dc=rhdh,dc=test
15
+ objectClass: organizationalUnit
16
+ ou: groups
17
+
18
+ dn: uid=user1,ou=users,dc=rhdh,dc=test
19
+ objectClass: inetOrgPerson
20
+ objectClass: organizationalPerson
21
+ objectClass: person
22
+ objectClass: top
23
+ uid: user1
24
+ cn: User 1
25
+ sn: One
26
+ givenName: User
27
+ mail: user1@rhdh.test
28
+ userPassword: user1pass
29
+
30
+ dn: uid=user2,ou=users,dc=rhdh,dc=test
31
+ objectClass: inetOrgPerson
32
+ objectClass: organizationalPerson
33
+ objectClass: person
34
+ objectClass: top
35
+ uid: user2
36
+ cn: User 2
37
+ sn: Two
38
+ givenName: User
39
+ mail: user2@rhdh.test
40
+ userPassword: user1pass
41
+
42
+ dn: uid=user3,ou=users,dc=rhdh,dc=test
43
+ objectClass: inetOrgPerson
44
+ objectClass: organizationalPerson
45
+ objectClass: person
46
+ objectClass: top
47
+ uid: user3
48
+ cn: User 3
49
+ sn: Three
50
+ givenName: User
51
+ mail: user3@rhdh.test
52
+ userPassword: user1pass
53
+
54
+ dn: uid=rhdh-admin,ou=users,dc=rhdh,dc=test
55
+ objectClass: inetOrgPerson
56
+ objectClass: organizationalPerson
57
+ objectClass: person
58
+ objectClass: top
59
+ uid: rhdh-admin
60
+ cn: RHDH Admin
61
+ sn: Admin
62
+ givenName: RHDH
63
+ mail: rhdh-admin@rhdh.test
64
+ userPassword: user1pass
65
+
66
+ dn: cn=Admins,ou=groups,dc=rhdh,dc=test
67
+ objectClass: groupOfNames
68
+ objectClass: top
69
+ cn: Admins
70
+ member: uid=rhdh-admin,ou=users,dc=rhdh,dc=test
71
+
72
+ dn: cn=All_Users,ou=groups,dc=rhdh,dc=test
73
+ objectClass: groupOfNames
74
+ objectClass: top
75
+ cn: All_Users
76
+ member: uid=user1,ou=users,dc=rhdh,dc=test
77
+ member: uid=user2,ou=users,dc=rhdh,dc=test
78
+
79
+ dn: cn=SubAdmins,ou=groups,dc=rhdh,dc=test
80
+ objectClass: groupOfNames
81
+ objectClass: top
82
+ cn: SubAdmins
83
+ member: uid=rhdh-admin,ou=users,dc=rhdh,dc=test
84
+
85
+ # Nested groups: create leaves before parents so member DNs resolve.
86
+ dn: cn=testSubSubGroup,ou=groups,dc=rhdh,dc=test
87
+ objectClass: groupOfNames
88
+ objectClass: top
89
+ cn: testSubSubGroup
90
+ member: uid=user3,ou=users,dc=rhdh,dc=test
91
+
92
+ dn: cn=testSubGroup,ou=groups,dc=rhdh,dc=test
93
+ objectClass: groupOfNames
94
+ objectClass: top
95
+ cn: testSubGroup
96
+ member: cn=testSubSubGroup,ou=groups,dc=rhdh,dc=test
97
+
98
+ dn: cn=testGroup,ou=groups,dc=rhdh,dc=test
99
+ objectClass: groupOfNames
100
+ objectClass: top
101
+ cn: testGroup
102
+ member: cn=testSubGroup,ou=groups,dc=rhdh,dc=test
@@ -0,0 +1,46 @@
1
+ import type { OpenLDAPDeploymentOptions } from "./types.js";
2
+ /** Default password shared by admin bind and seed user1 (matches ldap.spec pattern). */
3
+ export declare const DEFAULT_OPENLDAP_PASSWORD = "user1pass";
4
+ export declare const DEFAULT_OPENLDAP_CONFIG: {
5
+ releaseName: string;
6
+ adminUser: string;
7
+ adminPassword: string;
8
+ baseDn: string;
9
+ usersOu: string;
10
+ groupsOu: string;
11
+ port: number;
12
+ imageRepository: string;
13
+ imageTag: string;
14
+ };
15
+ export declare const DEFAULT_CONFIG_PATHS: {
16
+ seedLdifFile: string;
17
+ };
18
+ export declare const DEFAULT_USERS: readonly [{
19
+ readonly uid: "user1";
20
+ readonly cn: "User 1";
21
+ readonly sn: "One";
22
+ readonly mail: "user1@rhdh.test";
23
+ readonly password: "user1pass";
24
+ }, {
25
+ readonly uid: "user2";
26
+ readonly cn: "User 2";
27
+ readonly sn: "Two";
28
+ readonly mail: "user2@rhdh.test";
29
+ readonly password: "user1pass";
30
+ }, {
31
+ readonly uid: "user3";
32
+ readonly cn: "User 3";
33
+ readonly sn: "Three";
34
+ readonly mail: "user3@rhdh.test";
35
+ readonly password: "user1pass";
36
+ }, {
37
+ readonly uid: "rhdh-admin";
38
+ readonly cn: "RHDH Admin";
39
+ readonly sn: "Admin";
40
+ readonly mail: "rhdh-admin@rhdh.test";
41
+ readonly password: "user1pass";
42
+ }];
43
+ export declare function buildBindDn(options?: Pick<OpenLDAPDeploymentOptions, "adminUser" | "baseDn">): string;
44
+ export declare function buildUsersDn(options?: Pick<OpenLDAPDeploymentOptions, "usersOu" | "baseDn">): string;
45
+ export declare function buildGroupsDn(options?: Pick<OpenLDAPDeploymentOptions, "groupsOu" | "baseDn">): string;
46
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/deployment/openldap/constants.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAK5D,wFAAwF;AACxF,eAAO,MAAM,yBAAyB,cAAc,CAAC;AAErD,eAAO,MAAM,uBAAuB;;;;;;;;;;CAWnC,CAAC;AAEF,eAAO,MAAM,oBAAoB;;CAKhC,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;EA6BhB,CAAC;AAEX,wBAAgB,WAAW,CACzB,OAAO,GAAE,IAAI,CAAC,yBAAyB,EAAE,WAAW,GAAG,QAAQ,CAAM,GACpE,MAAM,CAIR;AAED,wBAAgB,YAAY,CAC1B,OAAO,GAAE,IAAI,CAAC,yBAAyB,EAAE,SAAS,GAAG,QAAQ,CAAM,GAClE,MAAM,CAIR;AAED,wBAAgB,aAAa,CAC3B,OAAO,GAAE,IAAI,CAAC,yBAAyB,EAAE,UAAU,GAAG,QAAQ,CAAM,GACnE,MAAM,CAIR"}
@@ -0,0 +1,65 @@
1
+ import path from "path";
2
+ // Navigate from dist/deployment/openldap/ to package root
3
+ const PACKAGE_ROOT = path.resolve(import.meta.dirname, "../../..");
4
+ /** Default password shared by admin bind and seed user1 (matches ldap.spec pattern). */
5
+ export const DEFAULT_OPENLDAP_PASSWORD = "user1pass";
6
+ export const DEFAULT_OPENLDAP_CONFIG = {
7
+ releaseName: "openldap",
8
+ adminUser: "admin",
9
+ adminPassword: DEFAULT_OPENLDAP_PASSWORD,
10
+ baseDn: "dc=rhdh,dc=test",
11
+ usersOu: "users",
12
+ groupsOu: "groups",
13
+ port: 1389,
14
+ // Bitnami public Helm chart for OpenLDAP was removed; use the Bitnami legacy image.
15
+ imageRepository: "bitnamilegacy/openldap",
16
+ imageTag: "2.6.10-debian-12-r4",
17
+ };
18
+ export const DEFAULT_CONFIG_PATHS = {
19
+ seedLdifFile: path.join(PACKAGE_ROOT, "dist/deployment/openldap/config/seed.ldif"),
20
+ };
21
+ export const DEFAULT_USERS = [
22
+ {
23
+ uid: "user1",
24
+ cn: "User 1",
25
+ sn: "One",
26
+ mail: "user1@rhdh.test",
27
+ password: DEFAULT_OPENLDAP_PASSWORD,
28
+ },
29
+ {
30
+ uid: "user2",
31
+ cn: "User 2",
32
+ sn: "Two",
33
+ mail: "user2@rhdh.test",
34
+ password: DEFAULT_OPENLDAP_PASSWORD,
35
+ },
36
+ {
37
+ uid: "user3",
38
+ cn: "User 3",
39
+ sn: "Three",
40
+ mail: "user3@rhdh.test",
41
+ password: DEFAULT_OPENLDAP_PASSWORD,
42
+ },
43
+ {
44
+ uid: "rhdh-admin",
45
+ cn: "RHDH Admin",
46
+ sn: "Admin",
47
+ mail: "rhdh-admin@rhdh.test",
48
+ password: DEFAULT_OPENLDAP_PASSWORD,
49
+ },
50
+ ];
51
+ export function buildBindDn(options = {}) {
52
+ const adminUser = options.adminUser ?? DEFAULT_OPENLDAP_CONFIG.adminUser;
53
+ const baseDn = options.baseDn ?? DEFAULT_OPENLDAP_CONFIG.baseDn;
54
+ return `cn=${adminUser},${baseDn}`;
55
+ }
56
+ export function buildUsersDn(options = {}) {
57
+ const usersOu = options.usersOu ?? DEFAULT_OPENLDAP_CONFIG.usersOu;
58
+ const baseDn = options.baseDn ?? DEFAULT_OPENLDAP_CONFIG.baseDn;
59
+ return `ou=${usersOu},${baseDn}`;
60
+ }
61
+ export function buildGroupsDn(options = {}) {
62
+ const groupsOu = options.groupsOu ?? DEFAULT_OPENLDAP_CONFIG.groupsOu;
63
+ const baseDn = options.baseDn ?? DEFAULT_OPENLDAP_CONFIG.baseDn;
64
+ return `ou=${groupsOu},${baseDn}`;
65
+ }
@@ -0,0 +1,31 @@
1
+ import { KubernetesClientHelper } from "../../utils/kubernetes-client.js";
2
+ import type { OpenLDAPDeploymentOptions, OpenLDAPDeploymentConfig, OpenLDAPBindConfig } from "./types.js";
3
+ /**
4
+ * Orchestrator-style OpenLDAP helper (Bitnami legacy image).
5
+ * Call from test.runOnce — not globalSetup. Deploys into the Playwright project namespace.
6
+ */
7
+ export declare class OpenLDAPHelper {
8
+ k8sClient: KubernetesClientHelper;
9
+ deploymentConfig: OpenLDAPDeploymentConfig;
10
+ ldapUrl: string;
11
+ constructor(options?: OpenLDAPDeploymentOptions);
12
+ /**
13
+ * Deploy OpenLDAP into the given namespace (creates namespace if needed).
14
+ */
15
+ deploy(namespace: string): Promise<void>;
16
+ /**
17
+ * True if the OpenLDAP service already exists in the configured namespace.
18
+ */
19
+ isRunning(): Promise<boolean>;
20
+ /** Cluster-internal LDAP URL (Keycloak federation / RHDH ldapOrg). */
21
+ getServiceUrl(): string;
22
+ getBindConfig(): OpenLDAPBindConfig;
23
+ /** Export LDAP_* env vars for RHDH secrets / app-config substitution. */
24
+ exportEnv(): void;
25
+ waitUntilReady(timeout?: number): Promise<void>;
26
+ teardown(): Promise<void>;
27
+ private _buildDeploymentConfig;
28
+ private _applyManifests;
29
+ private _log;
30
+ }
31
+ //# sourceMappingURL=deployment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../../src/deployment/openldap/deployment.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAS1E,OAAO,KAAK,EACV,yBAAyB,EACzB,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,qBAAa,cAAc;IAClB,SAAS,yBAAgC;IACzC,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C,OAAO,SAAM;gBAER,OAAO,GAAE,yBAA8B;IAInD;;OAEG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAcnC,sEAAsE;IACtE,aAAa,IAAI,MAAM;IAUvB,aAAa,IAAI,kBAAkB;IAYnC,yEAAyE;IACzE,SAAS,IAAI,IAAI;IASX,cAAc,CAAC,OAAO,SAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW5C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/B,OAAO,CAAC,sBAAsB;YAoBhB,eAAe;IA0H7B,OAAO,CAAC,IAAI;CAGb"}