@kuadrant/kuadrant-backstage-plugin-backend 0.0.2-dev-71a2ca1 → 0.0.2-dev-21b2773
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.cjs.js","sources":["../src/permissions.ts"],"sourcesContent":["import { createPermission } from '@backstage/plugin-permission-common';\n\n/**\n * Permission definitions for the Kuadrant plugin\n *\n * These permissions control access to PlanPolicy, APIProduct, APIKeyRequest,\n * and API key management within the Kuadrant Backstage plugin.\n *\n * Permissions are composable - use them to build custom roles beyond the\n * three reference personas (Platform Engineer, API Owner, API Consumer).\n */\n\n// planpolicy permissions (rate limit tiers)\nexport const kuadrantPlanPolicyCreatePermission = createPermission({\n name: 'kuadrant.planpolicy.create',\n attributes: { action: 'create' },\n});\n\nexport const kuadrantPlanPolicyReadPermission = createPermission({\n name: 'kuadrant.planpolicy.read',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantPlanPolicyUpdatePermission = createPermission({\n name: 'kuadrant.planpolicy.update',\n attributes: { action: 'update' },\n});\n\nexport const kuadrantPlanPolicyDeletePermission = createPermission({\n name: 'kuadrant.planpolicy.delete',\n attributes: { action: 'delete' },\n});\n\nexport const kuadrantPlanPolicyListPermission = createPermission({\n name: 'kuadrant.planpolicy.list',\n attributes: { action: 'read' },\n});\n\n// apiproduct permissions (catalog entries)\nexport const kuadrantApiProductCreatePermission = createPermission({\n name: 'kuadrant.apiproduct.create',\n attributes: { action: 'create' },\n});\n\nexport const kuadrantApiProductReadOwnPermission = createPermission({\n name: 'kuadrant.apiproduct.read.own',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantApiProductReadAllPermission = createPermission({\n name: 'kuadrant.apiproduct.read.all',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantApiProductUpdateOwnPermission = createPermission({\n name: 'kuadrant.apiproduct.update.own',\n attributes: { action: 'update' },\n});\n\nexport const kuadrantApiProductUpdateAllPermission = createPermission({\n name: 'kuadrant.apiproduct.update.all',\n attributes: { action: 'update' },\n});\n\nexport const kuadrantApiProductDeleteOwnPermission = createPermission({\n name: 'kuadrant.apiproduct.delete.own',\n attributes: { action: 'delete' },\n});\n\nexport const kuadrantApiProductDeleteAllPermission = createPermission({\n name: 'kuadrant.apiproduct.delete.all',\n attributes: { action: 'delete' },\n});\n\nexport const kuadrantApiProductListPermission = createPermission({\n name: 'kuadrant.apiproduct.list',\n attributes: { action: 'read' },\n});\n\n//
|
|
1
|
+
{"version":3,"file":"permissions.cjs.js","sources":["../src/permissions.ts"],"sourcesContent":["import { createPermission } from '@backstage/plugin-permission-common';\n\n/**\n * Permission definitions for the Kuadrant plugin\n *\n * These permissions control access to PlanPolicy, APIProduct, APIKeyRequest,\n * and API key management within the Kuadrant Backstage plugin.\n *\n * Permissions are composable - use them to build custom roles beyond the\n * three reference personas (Platform Engineer, API Owner, API Consumer).\n */\n\n// planpolicy permissions (rate limit tiers)\nexport const kuadrantPlanPolicyCreatePermission = createPermission({\n name: 'kuadrant.planpolicy.create',\n attributes: { action: 'create' },\n});\n\nexport const kuadrantPlanPolicyReadPermission = createPermission({\n name: 'kuadrant.planpolicy.read',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantPlanPolicyUpdatePermission = createPermission({\n name: 'kuadrant.planpolicy.update',\n attributes: { action: 'update' },\n});\n\nexport const kuadrantPlanPolicyDeletePermission = createPermission({\n name: 'kuadrant.planpolicy.delete',\n attributes: { action: 'delete' },\n});\n\nexport const kuadrantPlanPolicyListPermission = createPermission({\n name: 'kuadrant.planpolicy.list',\n attributes: { action: 'read' },\n});\n\n// apiproduct permissions (catalog entries)\nexport const kuadrantApiProductCreatePermission = createPermission({\n name: 'kuadrant.apiproduct.create',\n attributes: { action: 'create' },\n});\n\nexport const kuadrantApiProductReadOwnPermission = createPermission({\n name: 'kuadrant.apiproduct.read.own',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantApiProductReadAllPermission = createPermission({\n name: 'kuadrant.apiproduct.read.all',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantApiProductUpdateOwnPermission = createPermission({\n name: 'kuadrant.apiproduct.update.own',\n attributes: { action: 'update' },\n});\n\nexport const kuadrantApiProductUpdateAllPermission = createPermission({\n name: 'kuadrant.apiproduct.update.all',\n attributes: { action: 'update' },\n});\n\nexport const kuadrantApiProductDeleteOwnPermission = createPermission({\n name: 'kuadrant.apiproduct.delete.own',\n attributes: { action: 'delete' },\n});\n\nexport const kuadrantApiProductDeleteAllPermission = createPermission({\n name: 'kuadrant.apiproduct.delete.all',\n attributes: { action: 'delete' },\n});\n\nexport const kuadrantApiProductListPermission = createPermission({\n name: 'kuadrant.apiproduct.list',\n attributes: { action: 'read' },\n});\n\n// apikey request permissions (access requests)\nexport const kuadrantApiKeyRequestCreatePermission = createPermission({\n name: 'kuadrant.apikeyrequest.create',\n attributes: { action: 'create' },\n resourceType: 'apiproduct',\n});\n\nexport const kuadrantApiKeyRequestReadOwnPermission = createPermission({\n name: 'kuadrant.apikeyrequest.read.own',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantApiKeyRequestReadAllPermission = createPermission({\n name: 'kuadrant.apikeyrequest.read.all',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantApiKeyRequestUpdateOwnPermission = createPermission({\n name: 'kuadrant.apikeyrequest.update.own',\n attributes: { action: 'update' },\n});\n\nexport const kuadrantApiKeyRequestUpdateAllPermission = createPermission({\n name: 'kuadrant.apikeyrequest.update.all',\n attributes: { action: 'update' },\n});\n\nexport const kuadrantApiKeyRequestDeleteOwnPermission = createPermission({\n name: 'kuadrant.apikeyrequest.delete.own',\n attributes: { action: 'delete' },\n});\n\nexport const kuadrantApiKeyRequestDeleteAllPermission = createPermission({\n name: 'kuadrant.apikeyrequest.delete.all',\n attributes: { action: 'delete' },\n});\n\n// api key permissions (managed secrets)\nexport const kuadrantApiKeyReadOwnPermission = createPermission({\n name: 'kuadrant.apikey.read.own',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantApiKeyReadAllPermission = createPermission({\n name: 'kuadrant.apikey.read.all',\n attributes: { action: 'read' },\n});\n\nexport const kuadrantApiKeyDeleteOwnPermission = createPermission({\n name: 'kuadrant.apikey.delete.own',\n attributes: { action: 'delete' },\n});\n\nexport const kuadrantApiKeyDeleteAllPermission = createPermission({\n name: 'kuadrant.apikey.delete.all',\n attributes: { action: 'delete' },\n});\n\n/**\n * All Kuadrant permissions as an array for easy iteration\n */\nexport const kuadrantPermissions = [\n kuadrantPlanPolicyCreatePermission,\n kuadrantPlanPolicyReadPermission,\n kuadrantPlanPolicyUpdatePermission,\n kuadrantPlanPolicyDeletePermission,\n kuadrantPlanPolicyListPermission,\n kuadrantApiProductCreatePermission,\n kuadrantApiProductReadOwnPermission,\n kuadrantApiProductReadAllPermission,\n kuadrantApiProductUpdateOwnPermission,\n kuadrantApiProductUpdateAllPermission,\n kuadrantApiProductDeleteOwnPermission,\n kuadrantApiProductDeleteAllPermission,\n kuadrantApiProductListPermission,\n kuadrantApiKeyRequestCreatePermission,\n kuadrantApiKeyRequestReadOwnPermission,\n kuadrantApiKeyRequestReadAllPermission,\n kuadrantApiKeyRequestUpdateOwnPermission,\n kuadrantApiKeyRequestUpdateAllPermission,\n kuadrantApiKeyRequestDeleteOwnPermission,\n kuadrantApiKeyRequestDeleteAllPermission,\n kuadrantApiKeyReadOwnPermission,\n kuadrantApiKeyReadAllPermission,\n kuadrantApiKeyDeleteOwnPermission,\n kuadrantApiKeyDeleteAllPermission,\n];\n"],"names":["createPermission"],"mappings":"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"}
|
|
@@ -32,7 +32,7 @@ class APIProductEntityProvider {
|
|
|
32
32
|
try {
|
|
33
33
|
console.log("apiproduct provider: fetching apiproducts from kubernetes");
|
|
34
34
|
const response = await this.k8sClient.listCustomResources(
|
|
35
|
-
"
|
|
35
|
+
"devportal.kuadrant.io",
|
|
36
36
|
"v1alpha1",
|
|
37
37
|
"apiproducts"
|
|
38
38
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"APIProductEntityProvider.cjs.js","sources":["../../src/providers/APIProductEntityProvider.ts"],"sourcesContent":["import { ApiEntity } from '@backstage/catalog-model';\nimport { EntityProvider, EntityProviderConnection } from '@backstage/plugin-catalog-node';\nimport { RootConfigService } from '@backstage/backend-plugin-api';\nimport { KuadrantK8sClient } from '../k8s-client';\n\ninterface APIProduct {\n apiVersion: string;\n kind: string;\n metadata: {\n name: string;\n namespace: string;\n uid: string;\n resourceVersion: string;\n creationTimestamp: string;\n annotations?: Record<string, string>;\n labels?: Record<string, string>;\n };\n spec: {\n displayName?: string;\n description?: string;\n version?: string;\n tags?: string[];\n publishStatus?: 'Draft' | 'Published';\n plans?: Array<{\n tier: string;\n description?: string;\n limits?: any;\n }>;\n planPolicyRef?: {\n name: string;\n namespace: string;\n };\n documentation?: {\n openAPISpec?: string;\n docsURL?: string;\n gitRepository?: string;\n techdocsRef?: string;\n };\n contact?: {\n team?: string;\n email?: string;\n slack?: string;\n };\n };\n status: {\n openapi?: {\n raw?: string;\n lastSyncTime?: string;\n };\n }\n}\n\nexport class APIProductEntityProvider implements EntityProvider {\n private readonly k8sClient: KuadrantK8sClient;\n private connection?: EntityProviderConnection;\n private readonly providerId = 'kuadrant-apiproduct-provider';\n\n constructor(config: RootConfigService) {\n console.log('apiproduct provider: constructor called');\n this.k8sClient = new KuadrantK8sClient(config);\n }\n\n getProviderName(): string {\n return this.providerId;\n }\n\n async connect(connection: EntityProviderConnection): Promise<void> {\n console.log('apiproduct provider: connect called');\n this.connection = connection;\n\n console.log('apiproduct provider: starting initial sync');\n // initial full sync\n await this.refresh();\n\n // schedule periodic refresh (every 30 seconds for development)\n // note: in production, consider 5-10 minutes to reduce api load\n console.log('apiproduct provider: scheduling periodic refresh every 30 seconds');\n setInterval(async () => {\n await this.refresh();\n }, 30 * 1000);\n }\n\n public async refresh(): Promise<void> {\n console.log('apiproduct provider: refresh called');\n if (!this.connection) {\n console.log('apiproduct provider: no connection, skipping refresh');\n return;\n }\n\n try {\n console.log('apiproduct provider: fetching apiproducts from kubernetes');\n // fetch all apiproducts from kubernetes\n const response = await this.k8sClient.listCustomResources(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n 'apiproducts'\n );\n\n const apiProducts = (response.items || []) as APIProduct[];\n console.log(`apiproduct provider: found ${apiProducts.length} apiproducts`);\n\n // filter out Draft API products - only include Published ones\n const publishedProducts = apiProducts.filter(product => {\n const publishStatus = product.spec.publishStatus || 'Draft'; // default to Draft if not specified\n return publishStatus === 'Published';\n });\n console.log(`apiproduct provider: filtered to ${publishedProducts.length} published apiproducts (${apiProducts.length - publishedProducts.length} drafts excluded)`);\n\n // transform apiproducts to backstage api entities\n const entities = publishedProducts\n .map(product => this.transformToEntity(product))\n .filter((entity): entity is ApiEntity => entity !== null);\n console.log(`apiproduct provider: transformed ${entities.length} entities`);\n\n // submit entities to catalog\n console.log('apiproduct provider: submitting entities to catalog');\n await this.connection.applyMutation({\n type: 'full',\n entities: entities.map(entity => ({\n entity,\n locationKey: `kuadrant-apiproduct:${entity.metadata.namespace}/${entity.metadata.name}`,\n })),\n });\n\n console.log(`apiproduct provider: synced ${entities.length} api products`);\n } catch (error) {\n console.error('error refreshing apiproduct entities:', error);\n }\n }\n\n private transformToEntity(product: APIProduct): ApiEntity | null {\n const namespace = product.metadata.namespace || 'default';\n const name = product.metadata.name;\n const displayName = product.spec.displayName || name;\n const description = product.spec.description || `api product: ${displayName}`;\n\n // determine lifecycle from labels or default to production\n const lifecycle = product.metadata.labels?.lifecycle || 'production';\n\n // owner must be set via backstage ownership annotation\n // if missing, skip this apiproduct (created outside backstage or invalid)\n const owner = product.metadata.annotations?.['backstage.io/owner'];\n if (!owner) {\n console.warn(`apiproduct ${namespace}/${name} has no backstage.io/owner annotation, skipping catalog sync`);\n return null;\n }\n\n // build tags from product tags\n const tags = product.spec.tags || [];\n\n // OpenAPI spec URL\n const definition = product.status?.openapi?.raw ? `${product.status.openapi.raw}`\n : `# no openapi spec configured\n openapi: 3.0.0\n info:\n title: ${displayName}\n version: ${product.spec.version || '1.0.0'}\n description: ${description}\n `;\n\n // create entity with proper backstage structure\n const entity: ApiEntity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'API',\n metadata: {\n name: `${name}`,\n namespace: 'default',\n title: displayName,\n description,\n annotations: {\n 'backstage.io/managed-by-location': `kuadrant:${namespace}/${name}`,\n 'backstage.io/managed-by-origin-location': `kuadrant:${namespace}/${name}`,\n 'backstage.io/orphan-strategy': 'keep',\n 'kuadrant.io/namespace': namespace,\n 'kuadrant.io/apiproduct': name,\n // add httproute annotation if we can infer it (usually same as apiproduct name without -api suffix)\n 'kuadrant.io/httproute': name.endsWith('-api') ? name.slice(0, -4) : name,\n ...(product.spec.documentation?.openAPISpec && {\n 'kuadrant.io/openapi-spec-url': product.spec.documentation.openAPISpec,\n }),\n ...(product.spec.documentation?.docsURL && {\n 'kuadrant.io/docs-url': product.spec.documentation.docsURL,\n }),\n ...(product.spec.documentation?.gitRepository && {\n 'backstage.io/source-location': `url:${product.spec.documentation.gitRepository}`,\n }),\n ...(product.spec.documentation?.techdocsRef && {\n 'backstage.io/techdocs-ref': product.spec.documentation.techdocsRef,\n }),\n ...(product.spec.contact?.email && {\n 'kuadrant.io/contact-email': product.spec.contact.email,\n }),\n ...(product.spec.contact?.slack && {\n 'kuadrant.io/contact-slack': product.spec.contact.slack,\n }),\n },\n tags: [...tags, 'kuadrant', 'apiproduct'],\n labels: {\n 'kuadrant.io/synced': 'true',\n ...(product.metadata.labels || {}),\n },\n },\n spec: {\n type: 'openapi',\n lifecycle,\n owner,\n definition: definition,\n },\n };\n\n return entity;\n }\n}\n"],"names":["KuadrantK8sClient"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"APIProductEntityProvider.cjs.js","sources":["../../src/providers/APIProductEntityProvider.ts"],"sourcesContent":["import { ApiEntity } from '@backstage/catalog-model';\nimport { EntityProvider, EntityProviderConnection } from '@backstage/plugin-catalog-node';\nimport { RootConfigService } from '@backstage/backend-plugin-api';\nimport { KuadrantK8sClient } from '../k8s-client';\n\ninterface APIProduct {\n apiVersion: string;\n kind: string;\n metadata: {\n name: string;\n namespace: string;\n uid: string;\n resourceVersion: string;\n creationTimestamp: string;\n annotations?: Record<string, string>;\n labels?: Record<string, string>;\n };\n spec: {\n displayName?: string;\n description?: string;\n version?: string;\n tags?: string[];\n publishStatus?: 'Draft' | 'Published';\n plans?: Array<{\n tier: string;\n description?: string;\n limits?: any;\n }>;\n planPolicyRef?: {\n name: string;\n namespace: string;\n };\n documentation?: {\n openAPISpec?: string;\n docsURL?: string;\n gitRepository?: string;\n techdocsRef?: string;\n };\n contact?: {\n team?: string;\n email?: string;\n slack?: string;\n };\n };\n status: {\n openapi?: {\n raw?: string;\n lastSyncTime?: string;\n };\n }\n}\n\nexport class APIProductEntityProvider implements EntityProvider {\n private readonly k8sClient: KuadrantK8sClient;\n private connection?: EntityProviderConnection;\n private readonly providerId = 'kuadrant-apiproduct-provider';\n\n constructor(config: RootConfigService) {\n console.log('apiproduct provider: constructor called');\n this.k8sClient = new KuadrantK8sClient(config);\n }\n\n getProviderName(): string {\n return this.providerId;\n }\n\n async connect(connection: EntityProviderConnection): Promise<void> {\n console.log('apiproduct provider: connect called');\n this.connection = connection;\n\n console.log('apiproduct provider: starting initial sync');\n // initial full sync\n await this.refresh();\n\n // schedule periodic refresh (every 30 seconds for development)\n // note: in production, consider 5-10 minutes to reduce api load\n console.log('apiproduct provider: scheduling periodic refresh every 30 seconds');\n setInterval(async () => {\n await this.refresh();\n }, 30 * 1000);\n }\n\n public async refresh(): Promise<void> {\n console.log('apiproduct provider: refresh called');\n if (!this.connection) {\n console.log('apiproduct provider: no connection, skipping refresh');\n return;\n }\n\n try {\n console.log('apiproduct provider: fetching apiproducts from kubernetes');\n // fetch all apiproducts from kubernetes\n const response = await this.k8sClient.listCustomResources(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n 'apiproducts'\n );\n\n const apiProducts = (response.items || []) as APIProduct[];\n console.log(`apiproduct provider: found ${apiProducts.length} apiproducts`);\n\n // filter out Draft API products - only include Published ones\n const publishedProducts = apiProducts.filter(product => {\n const publishStatus = product.spec.publishStatus || 'Draft'; // default to Draft if not specified\n return publishStatus === 'Published';\n });\n console.log(`apiproduct provider: filtered to ${publishedProducts.length} published apiproducts (${apiProducts.length - publishedProducts.length} drafts excluded)`);\n\n // transform apiproducts to backstage api entities\n const entities = publishedProducts\n .map(product => this.transformToEntity(product))\n .filter((entity): entity is ApiEntity => entity !== null);\n console.log(`apiproduct provider: transformed ${entities.length} entities`);\n\n // submit entities to catalog\n console.log('apiproduct provider: submitting entities to catalog');\n await this.connection.applyMutation({\n type: 'full',\n entities: entities.map(entity => ({\n entity,\n locationKey: `kuadrant-apiproduct:${entity.metadata.namespace}/${entity.metadata.name}`,\n })),\n });\n\n console.log(`apiproduct provider: synced ${entities.length} api products`);\n } catch (error) {\n console.error('error refreshing apiproduct entities:', error);\n }\n }\n\n private transformToEntity(product: APIProduct): ApiEntity | null {\n const namespace = product.metadata.namespace || 'default';\n const name = product.metadata.name;\n const displayName = product.spec.displayName || name;\n const description = product.spec.description || `api product: ${displayName}`;\n\n // determine lifecycle from labels or default to production\n const lifecycle = product.metadata.labels?.lifecycle || 'production';\n\n // owner must be set via backstage ownership annotation\n // if missing, skip this apiproduct (created outside backstage or invalid)\n const owner = product.metadata.annotations?.['backstage.io/owner'];\n if (!owner) {\n console.warn(`apiproduct ${namespace}/${name} has no backstage.io/owner annotation, skipping catalog sync`);\n return null;\n }\n\n // build tags from product tags\n const tags = product.spec.tags || [];\n\n // OpenAPI spec URL\n const definition = product.status?.openapi?.raw ? `${product.status.openapi.raw}`\n : `# no openapi spec configured\n openapi: 3.0.0\n info:\n title: ${displayName}\n version: ${product.spec.version || '1.0.0'}\n description: ${description}\n `;\n\n // create entity with proper backstage structure\n const entity: ApiEntity = {\n apiVersion: 'backstage.io/v1alpha1',\n kind: 'API',\n metadata: {\n name: `${name}`,\n namespace: 'default',\n title: displayName,\n description,\n annotations: {\n 'backstage.io/managed-by-location': `kuadrant:${namespace}/${name}`,\n 'backstage.io/managed-by-origin-location': `kuadrant:${namespace}/${name}`,\n 'backstage.io/orphan-strategy': 'keep',\n 'kuadrant.io/namespace': namespace,\n 'kuadrant.io/apiproduct': name,\n // add httproute annotation if we can infer it (usually same as apiproduct name without -api suffix)\n 'kuadrant.io/httproute': name.endsWith('-api') ? name.slice(0, -4) : name,\n ...(product.spec.documentation?.openAPISpec && {\n 'kuadrant.io/openapi-spec-url': product.spec.documentation.openAPISpec,\n }),\n ...(product.spec.documentation?.docsURL && {\n 'kuadrant.io/docs-url': product.spec.documentation.docsURL,\n }),\n ...(product.spec.documentation?.gitRepository && {\n 'backstage.io/source-location': `url:${product.spec.documentation.gitRepository}`,\n }),\n ...(product.spec.documentation?.techdocsRef && {\n 'backstage.io/techdocs-ref': product.spec.documentation.techdocsRef,\n }),\n ...(product.spec.contact?.email && {\n 'kuadrant.io/contact-email': product.spec.contact.email,\n }),\n ...(product.spec.contact?.slack && {\n 'kuadrant.io/contact-slack': product.spec.contact.slack,\n }),\n },\n tags: [...tags, 'kuadrant', 'apiproduct'],\n labels: {\n 'kuadrant.io/synced': 'true',\n ...(product.metadata.labels || {}),\n },\n },\n spec: {\n type: 'openapi',\n lifecycle,\n owner,\n definition: definition,\n },\n };\n\n return entity;\n }\n}\n"],"names":["KuadrantK8sClient"],"mappings":"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"}
|
package/dist/router.cjs.js
CHANGED
|
@@ -62,7 +62,7 @@ async function createRouter({
|
|
|
62
62
|
throw new errors.NotAllowedError("unauthorised");
|
|
63
63
|
}
|
|
64
64
|
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
65
|
-
const data = await k8sClient$1.listCustomResources("
|
|
65
|
+
const data = await k8sClient$1.listCustomResources("devportal.kuadrant.io", "v1alpha1", "apiproducts");
|
|
66
66
|
const readAllDecision = await permissions$1.authorize(
|
|
67
67
|
[{ permission: permissions.kuadrantApiProductReadAllPermission }],
|
|
68
68
|
{ credentials }
|
|
@@ -109,14 +109,14 @@ async function createRouter({
|
|
|
109
109
|
throw new errors.NotAllowedError("unauthorised");
|
|
110
110
|
}
|
|
111
111
|
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
112
|
-
const data = await k8sClient$1.getCustomResource("
|
|
112
|
+
const data = await k8sClient$1.getCustomResource("devportal.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
113
113
|
const owner = data.metadata?.annotations?.["backstage.io/owner"];
|
|
114
114
|
if (owner !== userEntityRef) {
|
|
115
115
|
throw new errors.NotAllowedError("you can only read your own api products");
|
|
116
116
|
}
|
|
117
117
|
res.json(data);
|
|
118
118
|
} else {
|
|
119
|
-
const data = await k8sClient$1.getCustomResource("
|
|
119
|
+
const data = await k8sClient$1.getCustomResource("devportal.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
120
120
|
res.json(data);
|
|
121
121
|
}
|
|
122
122
|
} catch (error) {
|
|
@@ -177,7 +177,7 @@ async function createRouter({
|
|
|
177
177
|
console.warn("failed to populate plans from planpolicy:", error);
|
|
178
178
|
}
|
|
179
179
|
const created = await k8sClient$1.createCustomResource(
|
|
180
|
-
"
|
|
180
|
+
"devportal.kuadrant.io",
|
|
181
181
|
"v1alpha1",
|
|
182
182
|
namespace,
|
|
183
183
|
"apiproducts",
|
|
@@ -217,14 +217,69 @@ async function createRouter({
|
|
|
217
217
|
throw new errors.NotAllowedError("unauthorised");
|
|
218
218
|
}
|
|
219
219
|
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
220
|
-
const existing = await k8sClient$1.getCustomResource("
|
|
220
|
+
const existing = await k8sClient$1.getCustomResource("devportal.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
221
221
|
const owner = existing.metadata?.annotations?.["backstage.io/owner"];
|
|
222
222
|
if (owner !== userEntityRef) {
|
|
223
223
|
throw new errors.NotAllowedError("you can only delete your own api products");
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
+
console.log(`cascading delete: finding apikeyrequests for ${namespace}/${name}`);
|
|
227
|
+
let allRequests;
|
|
228
|
+
try {
|
|
229
|
+
allRequests = await k8sClient$1.listCustomResources(
|
|
230
|
+
"extensions.kuadrant.io",
|
|
231
|
+
"v1alpha1",
|
|
232
|
+
"apikeyrequests",
|
|
233
|
+
namespace
|
|
234
|
+
);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.warn("failed to list apikeyrequests during cascade delete:", error);
|
|
237
|
+
allRequests = { items: [] };
|
|
238
|
+
}
|
|
239
|
+
const relatedRequests = (allRequests.items || []).filter(
|
|
240
|
+
(req2) => req2.spec?.apiName === name && req2.spec?.apiNamespace === namespace
|
|
241
|
+
);
|
|
242
|
+
console.log(`found ${relatedRequests.length} apikeyrequests to delete`);
|
|
243
|
+
const deletionResults = await Promise.allSettled(
|
|
244
|
+
relatedRequests.map(async (request) => {
|
|
245
|
+
const requestName = request.metadata.name;
|
|
246
|
+
const requestUserId = request.spec?.requestedBy?.userId;
|
|
247
|
+
const planTier = request.spec?.planTier;
|
|
248
|
+
console.log(`deleting apikeyrequest: ${namespace}/${requestName}`);
|
|
249
|
+
if (request.status?.phase === "Approved") {
|
|
250
|
+
try {
|
|
251
|
+
console.log(`finding secret for approved request: ${namespace}/${requestName}`);
|
|
252
|
+
const secrets = await k8sClient$1.listSecrets(namespace);
|
|
253
|
+
const matchingSecret = secrets.items?.find((s) => {
|
|
254
|
+
const annotations = s.metadata?.annotations || {};
|
|
255
|
+
return annotations["secret.kuadrant.io/user-id"] === requestUserId && annotations["secret.kuadrant.io/plan-id"] === planTier && s.metadata?.labels?.app === name;
|
|
256
|
+
});
|
|
257
|
+
if (matchingSecret) {
|
|
258
|
+
console.log(`deleting secret: ${namespace}/${matchingSecret.metadata.name}`);
|
|
259
|
+
await k8sClient$1.deleteSecret(namespace, matchingSecret.metadata.name);
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.warn(`failed to delete secret for request ${requestName}:`, error);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
await k8sClient$1.deleteCustomResource(
|
|
266
|
+
"extensions.kuadrant.io",
|
|
267
|
+
"v1alpha1",
|
|
268
|
+
namespace,
|
|
269
|
+
"apikeyrequests",
|
|
270
|
+
requestName
|
|
271
|
+
);
|
|
272
|
+
})
|
|
273
|
+
);
|
|
274
|
+
const failures = deletionResults.filter((r) => r.status === "rejected");
|
|
275
|
+
if (failures.length > 0) {
|
|
276
|
+
console.warn(
|
|
277
|
+
`${failures.length} apikeyrequests/secret failed to delete:`,
|
|
278
|
+
failures.map((f) => f.reason)
|
|
279
|
+
);
|
|
280
|
+
}
|
|
226
281
|
await k8sClient$1.deleteCustomResource(
|
|
227
|
-
"
|
|
282
|
+
"devportal.kuadrant.io",
|
|
228
283
|
"v1alpha1",
|
|
229
284
|
namespace,
|
|
230
285
|
"apiproducts",
|
|
@@ -308,7 +363,7 @@ async function createRouter({
|
|
|
308
363
|
throw new errors.NotAllowedError("unauthorised");
|
|
309
364
|
}
|
|
310
365
|
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
311
|
-
const existing = await k8sClient$1.getCustomResource("
|
|
366
|
+
const existing = await k8sClient$1.getCustomResource("devportal.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
312
367
|
const owner = existing.metadata?.annotations?.["backstage.io/owner"];
|
|
313
368
|
if (owner !== userEntityRef) {
|
|
314
369
|
throw new errors.NotAllowedError("you can only update your own api products");
|
|
@@ -318,7 +373,7 @@ async function createRouter({
|
|
|
318
373
|
delete req.body.metadata.annotations["backstage.io/owner"];
|
|
319
374
|
}
|
|
320
375
|
const updated = await k8sClient$1.patchCustomResource(
|
|
321
|
-
"
|
|
376
|
+
"devportal.kuadrant.io",
|
|
322
377
|
"v1alpha1",
|
|
323
378
|
namespace,
|
|
324
379
|
"apiproducts",
|
|
@@ -402,8 +457,10 @@ async function createRouter({
|
|
|
402
457
|
}
|
|
403
458
|
});
|
|
404
459
|
const requestSchema = zod.z.object({
|
|
405
|
-
|
|
406
|
-
|
|
460
|
+
apiProductName: zod.z.string(),
|
|
461
|
+
// name of the APIProduct
|
|
462
|
+
namespace: zod.z.string(),
|
|
463
|
+
// namespace where both APIProduct and APIKey live
|
|
407
464
|
planTier: zod.z.string(),
|
|
408
465
|
useCase: zod.z.string().optional(),
|
|
409
466
|
userEmail: zod.z.string().optional()
|
|
@@ -415,9 +472,9 @@ async function createRouter({
|
|
|
415
472
|
}
|
|
416
473
|
try {
|
|
417
474
|
const credentials = await httpAuth.credentials(req);
|
|
418
|
-
const {
|
|
475
|
+
const { apiProductName, namespace, planTier, useCase, userEmail } = parsed.data;
|
|
419
476
|
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
420
|
-
const resourceRef = `apiproduct:${
|
|
477
|
+
const resourceRef = `apiproduct:${namespace}/${apiProductName}`;
|
|
421
478
|
const decision = await permissions$1.authorize(
|
|
422
479
|
[{
|
|
423
480
|
permission: permissions.kuadrantApiKeyRequestCreatePermission,
|
|
@@ -426,60 +483,59 @@ async function createRouter({
|
|
|
426
483
|
{ credentials }
|
|
427
484
|
);
|
|
428
485
|
if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
429
|
-
throw new errors.NotAllowedError(`not authorised to request access to ${
|
|
486
|
+
throw new errors.NotAllowedError(`not authorised to request access to ${apiProductName}`);
|
|
430
487
|
}
|
|
431
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
432
488
|
const randomSuffix = crypto.randomBytes(4).toString("hex");
|
|
433
489
|
const userName = extractNameFromEntityRef(userEntityRef);
|
|
434
|
-
const requestName = `${userName}-${
|
|
490
|
+
const requestName = `${userName}-${apiProductName}-${randomSuffix}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
435
491
|
const requestedBy = { userId: userEntityRef };
|
|
436
492
|
if (userEmail) {
|
|
437
493
|
requestedBy.email = userEmail;
|
|
438
494
|
}
|
|
439
495
|
const request = {
|
|
440
|
-
apiVersion: "
|
|
441
|
-
kind: "
|
|
496
|
+
apiVersion: "devportal.kuadrant.io/v1alpha1",
|
|
497
|
+
kind: "APIKey",
|
|
442
498
|
metadata: {
|
|
443
499
|
name: requestName,
|
|
444
|
-
namespace
|
|
500
|
+
namespace
|
|
445
501
|
},
|
|
446
502
|
spec: {
|
|
447
|
-
|
|
448
|
-
|
|
503
|
+
apiProductRef: {
|
|
504
|
+
name: apiProductName
|
|
505
|
+
},
|
|
449
506
|
planTier,
|
|
450
507
|
useCase: useCase || "",
|
|
451
|
-
requestedBy
|
|
452
|
-
requestedAt: timestamp
|
|
508
|
+
requestedBy
|
|
453
509
|
}
|
|
454
510
|
};
|
|
455
511
|
const created = await k8sClient$1.createCustomResource(
|
|
456
|
-
"
|
|
512
|
+
"devportal.kuadrant.io",
|
|
457
513
|
"v1alpha1",
|
|
458
|
-
|
|
459
|
-
"
|
|
514
|
+
namespace,
|
|
515
|
+
"apikeys",
|
|
460
516
|
request
|
|
461
517
|
);
|
|
462
518
|
try {
|
|
463
519
|
const apiProduct = await k8sClient$1.getCustomResource(
|
|
464
|
-
"
|
|
520
|
+
"devportal.kuadrant.io",
|
|
465
521
|
"v1alpha1",
|
|
466
|
-
|
|
522
|
+
namespace,
|
|
467
523
|
"apiproducts",
|
|
468
|
-
|
|
524
|
+
apiProductName
|
|
469
525
|
);
|
|
470
526
|
if (apiProduct.spec?.approvalMode === "automatic") {
|
|
471
527
|
const apiKey = generateApiKey();
|
|
472
|
-
const
|
|
528
|
+
const timestamp = Date.now();
|
|
473
529
|
const userName2 = extractNameFromEntityRef(userEntityRef);
|
|
474
|
-
const secretName = `${userName2}-${
|
|
530
|
+
const secretName = `${userName2}-${apiProductName}-${timestamp}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
475
531
|
const secret = {
|
|
476
532
|
apiVersion: "v1",
|
|
477
533
|
kind: "Secret",
|
|
478
534
|
metadata: {
|
|
479
535
|
name: secretName,
|
|
480
|
-
namespace
|
|
536
|
+
namespace,
|
|
481
537
|
labels: {
|
|
482
|
-
app:
|
|
538
|
+
app: apiProductName
|
|
483
539
|
},
|
|
484
540
|
annotations: {
|
|
485
541
|
"secret.kuadrant.io/plan-id": planTier,
|
|
@@ -491,20 +547,20 @@ async function createRouter({
|
|
|
491
547
|
},
|
|
492
548
|
type: "Opaque"
|
|
493
549
|
};
|
|
494
|
-
await k8sClient$1.createSecret(
|
|
550
|
+
await k8sClient$1.createSecret(namespace, secret);
|
|
495
551
|
let planLimits = null;
|
|
496
552
|
const plan = apiProduct.spec?.plans?.find((p) => p.tier === planTier);
|
|
497
553
|
if (plan) {
|
|
498
554
|
planLimits = plan.limits;
|
|
499
555
|
}
|
|
500
|
-
let apiHostname = `${
|
|
556
|
+
let apiHostname = `${apiProductName}.apps.example.com`;
|
|
501
557
|
try {
|
|
502
558
|
const httproute = await k8sClient$1.getCustomResource(
|
|
503
559
|
"gateway.networking.k8s.io",
|
|
504
560
|
"v1",
|
|
505
|
-
|
|
561
|
+
namespace,
|
|
506
562
|
"httproutes",
|
|
507
|
-
|
|
563
|
+
apiProductName
|
|
508
564
|
);
|
|
509
565
|
if (httproute.spec?.hostnames && httproute.spec.hostnames.length > 0) {
|
|
510
566
|
apiHostname = httproute.spec.hostnames[0];
|
|
@@ -520,14 +576,14 @@ async function createRouter({
|
|
|
520
576
|
apiKey,
|
|
521
577
|
apiHostname,
|
|
522
578
|
apiBasePath: "/api/v1",
|
|
523
|
-
apiDescription: `${
|
|
579
|
+
apiDescription: `${apiProductName} api`,
|
|
524
580
|
planLimits
|
|
525
581
|
};
|
|
526
582
|
await k8sClient$1.patchCustomResourceStatus(
|
|
527
|
-
"
|
|
583
|
+
"devportal.kuadrant.io",
|
|
528
584
|
"v1alpha1",
|
|
529
|
-
|
|
530
|
-
"
|
|
585
|
+
namespace,
|
|
586
|
+
"apikeys",
|
|
531
587
|
requestName,
|
|
532
588
|
status
|
|
533
589
|
);
|
|
@@ -566,14 +622,14 @@ async function createRouter({
|
|
|
566
622
|
const namespace = req.query.namespace;
|
|
567
623
|
let data;
|
|
568
624
|
if (namespace) {
|
|
569
|
-
data = await k8sClient$1.listCustomResources("
|
|
625
|
+
data = await k8sClient$1.listCustomResources("devportal.kuadrant.io", "v1alpha1", "aPIKeys", namespace);
|
|
570
626
|
} else {
|
|
571
|
-
data = await k8sClient$1.listCustomResources("
|
|
627
|
+
data = await k8sClient$1.listCustomResources("devportal.kuadrant.io", "v1alpha1", "aPIKeys");
|
|
572
628
|
}
|
|
573
629
|
let filteredItems = data.items || [];
|
|
574
630
|
if (!canReadAll) {
|
|
575
631
|
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
576
|
-
const apiproducts = await k8sClient$1.listCustomResources("
|
|
632
|
+
const apiproducts = await k8sClient$1.listCustomResources("devportal.kuadrant.io", "v1alpha1", "apiproducts");
|
|
577
633
|
const ownedApiProducts = (apiproducts.items || []).filter((product) => {
|
|
578
634
|
const owner = product.metadata?.annotations?.["backstage.io/owner"];
|
|
579
635
|
return owner === userEntityRef;
|
|
@@ -612,9 +668,9 @@ async function createRouter({
|
|
|
612
668
|
const namespace = req.query.namespace;
|
|
613
669
|
let data;
|
|
614
670
|
if (namespace) {
|
|
615
|
-
data = await k8sClient$1.listCustomResources("
|
|
671
|
+
data = await k8sClient$1.listCustomResources("devportal.kuadrant.io", "v1alpha1", "apikeys", namespace);
|
|
616
672
|
} else {
|
|
617
|
-
data = await k8sClient$1.listCustomResources("
|
|
673
|
+
data = await k8sClient$1.listCustomResources("devportal.kuadrant.io", "v1alpha1", "apikeys");
|
|
618
674
|
}
|
|
619
675
|
const filteredItems = (data.items || []).filter(
|
|
620
676
|
(req2) => req2.spec?.requestedBy?.userId === userEntityRef
|
|
@@ -644,19 +700,23 @@ async function createRouter({
|
|
|
644
700
|
const { comment } = parsed.data;
|
|
645
701
|
const reviewedBy = userEntityRef;
|
|
646
702
|
const request = await k8sClient$1.getCustomResource(
|
|
647
|
-
"
|
|
703
|
+
"devportal.kuadrant.io",
|
|
648
704
|
"v1alpha1",
|
|
649
705
|
namespace,
|
|
650
|
-
"
|
|
706
|
+
"apikeys",
|
|
651
707
|
name
|
|
652
708
|
);
|
|
653
709
|
const spec = request.spec;
|
|
710
|
+
const apiProductName = spec.apiProductRef?.name;
|
|
711
|
+
if (!apiProductName) {
|
|
712
|
+
throw new errors.InputError("apiProductRef.name is required in APIKey spec");
|
|
713
|
+
}
|
|
654
714
|
const apiProduct = await k8sClient$1.getCustomResource(
|
|
655
|
-
"
|
|
715
|
+
"devportal.kuadrant.io",
|
|
656
716
|
"v1alpha1",
|
|
657
|
-
|
|
717
|
+
namespace,
|
|
658
718
|
"apiproducts",
|
|
659
|
-
|
|
719
|
+
apiProductName
|
|
660
720
|
);
|
|
661
721
|
const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
|
|
662
722
|
const updateAllDecision = await permissions$1.authorize(
|
|
@@ -678,15 +738,15 @@ async function createRouter({
|
|
|
678
738
|
const apiKey = generateApiKey();
|
|
679
739
|
const timestamp = Date.now();
|
|
680
740
|
const userName = extractNameFromEntityRef(spec.requestedBy.userId);
|
|
681
|
-
const secretName = `${userName}-${
|
|
741
|
+
const secretName = `${userName}-${apiProductName}-${timestamp}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
682
742
|
const secret = {
|
|
683
743
|
apiVersion: "v1",
|
|
684
744
|
kind: "Secret",
|
|
685
745
|
metadata: {
|
|
686
746
|
name: secretName,
|
|
687
|
-
namespace
|
|
747
|
+
namespace,
|
|
688
748
|
labels: {
|
|
689
|
-
app:
|
|
749
|
+
app: apiProductName
|
|
690
750
|
},
|
|
691
751
|
annotations: {
|
|
692
752
|
"secret.kuadrant.io/plan-id": spec.planTier,
|
|
@@ -698,12 +758,12 @@ async function createRouter({
|
|
|
698
758
|
},
|
|
699
759
|
type: "Opaque"
|
|
700
760
|
};
|
|
701
|
-
await k8sClient$1.createSecret(
|
|
761
|
+
await k8sClient$1.createSecret(namespace, secret);
|
|
702
762
|
let planLimits = null;
|
|
703
763
|
try {
|
|
704
|
-
const products = await k8sClient$1.listCustomResources("
|
|
764
|
+
const products = await k8sClient$1.listCustomResources("devportal.kuadrant.io", "v1alpha1", "apiproducts");
|
|
705
765
|
const product = (products.items || []).find(
|
|
706
|
-
(p) => p.metadata.name.includes(
|
|
766
|
+
(p) => p.metadata.name.includes(apiProductName) || p.spec?.displayName?.toLowerCase().includes(apiProductName.toLowerCase())
|
|
707
767
|
);
|
|
708
768
|
if (product) {
|
|
709
769
|
const plan = product.spec?.plans?.find((p) => p.tier === spec.planTier);
|
|
@@ -719,9 +779,9 @@ async function createRouter({
|
|
|
719
779
|
const policy = await k8sClient$1.getCustomResource(
|
|
720
780
|
"extensions.kuadrant.io",
|
|
721
781
|
"v1alpha1",
|
|
722
|
-
|
|
782
|
+
namespace,
|
|
723
783
|
"planpolicies",
|
|
724
|
-
`${
|
|
784
|
+
`${apiProductName}-plan`
|
|
725
785
|
);
|
|
726
786
|
const plan = policy.spec?.plans?.find((p) => p.tier === spec.planTier);
|
|
727
787
|
if (plan) {
|
|
@@ -731,14 +791,14 @@ async function createRouter({
|
|
|
731
791
|
console.warn("could not fetch planpolicy for plan limits:", e);
|
|
732
792
|
}
|
|
733
793
|
}
|
|
734
|
-
let apiHostname = `${
|
|
794
|
+
let apiHostname = `${apiProductName}.apps.example.com`;
|
|
735
795
|
try {
|
|
736
796
|
const httproute = await k8sClient$1.getCustomResource(
|
|
737
797
|
"gateway.networking.k8s.io",
|
|
738
798
|
"v1",
|
|
739
|
-
|
|
799
|
+
namespace,
|
|
740
800
|
"httproutes",
|
|
741
|
-
|
|
801
|
+
apiProductName
|
|
742
802
|
);
|
|
743
803
|
if (httproute.spec?.hostnames && httproute.spec.hostnames.length > 0) {
|
|
744
804
|
apiHostname = httproute.spec.hostnames[0];
|
|
@@ -754,14 +814,14 @@ async function createRouter({
|
|
|
754
814
|
apiKey,
|
|
755
815
|
apiHostname,
|
|
756
816
|
apiBasePath: "/api/v1",
|
|
757
|
-
apiDescription: `${
|
|
817
|
+
apiDescription: `${apiProductName} api`,
|
|
758
818
|
planLimits
|
|
759
819
|
};
|
|
760
820
|
await k8sClient$1.patchCustomResourceStatus(
|
|
761
|
-
"
|
|
821
|
+
"devportal.kuadrant.io",
|
|
762
822
|
"v1alpha1",
|
|
763
823
|
namespace,
|
|
764
|
-
"
|
|
824
|
+
"apikeys",
|
|
765
825
|
name,
|
|
766
826
|
status
|
|
767
827
|
);
|
|
@@ -787,19 +847,23 @@ async function createRouter({
|
|
|
787
847
|
const { comment } = parsed.data;
|
|
788
848
|
const reviewedBy = userEntityRef;
|
|
789
849
|
const request = await k8sClient$1.getCustomResource(
|
|
790
|
-
"
|
|
850
|
+
"devportal.kuadrant.io",
|
|
791
851
|
"v1alpha1",
|
|
792
852
|
namespace,
|
|
793
|
-
"
|
|
853
|
+
"apikeys",
|
|
794
854
|
name
|
|
795
855
|
);
|
|
796
856
|
const spec = request.spec;
|
|
857
|
+
const apiProductName = spec.apiProductRef?.name;
|
|
858
|
+
if (!apiProductName) {
|
|
859
|
+
throw new errors.InputError("apiProductRef.name is required in APIKey spec");
|
|
860
|
+
}
|
|
797
861
|
const apiProduct = await k8sClient$1.getCustomResource(
|
|
798
|
-
"
|
|
862
|
+
"devportal.kuadrant.io",
|
|
799
863
|
"v1alpha1",
|
|
800
|
-
|
|
864
|
+
namespace,
|
|
801
865
|
"apiproducts",
|
|
802
|
-
|
|
866
|
+
apiProductName
|
|
803
867
|
);
|
|
804
868
|
const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
|
|
805
869
|
const updateAllDecision = await permissions$1.authorize(
|
|
@@ -825,10 +889,10 @@ async function createRouter({
|
|
|
825
889
|
reason: comment || "rejected"
|
|
826
890
|
};
|
|
827
891
|
await k8sClient$1.patchCustomResourceStatus(
|
|
828
|
-
"
|
|
892
|
+
"devportal.kuadrant.io",
|
|
829
893
|
"v1alpha1",
|
|
830
894
|
namespace,
|
|
831
|
-
"
|
|
895
|
+
"apikeys",
|
|
832
896
|
name,
|
|
833
897
|
status
|
|
834
898
|
);
|
|
@@ -870,15 +934,15 @@ async function createRouter({
|
|
|
870
934
|
for (const reqRef of requests) {
|
|
871
935
|
try {
|
|
872
936
|
const request = await k8sClient$1.getCustomResource(
|
|
873
|
-
"
|
|
937
|
+
"devportal.kuadrant.io",
|
|
874
938
|
"v1alpha1",
|
|
875
939
|
reqRef.namespace,
|
|
876
|
-
"
|
|
940
|
+
"apikeys",
|
|
877
941
|
reqRef.name
|
|
878
942
|
);
|
|
879
943
|
const spec = request.spec;
|
|
880
944
|
const apiProduct = await k8sClient$1.getCustomResource(
|
|
881
|
-
"
|
|
945
|
+
"devportal.kuadrant.io",
|
|
882
946
|
"v1alpha1",
|
|
883
947
|
spec.apiNamespace,
|
|
884
948
|
"apiproducts",
|
|
@@ -927,7 +991,7 @@ async function createRouter({
|
|
|
927
991
|
await k8sClient$1.createSecret(spec.apiNamespace, secret);
|
|
928
992
|
let planLimits = null;
|
|
929
993
|
try {
|
|
930
|
-
const products = await k8sClient$1.listCustomResources("
|
|
994
|
+
const products = await k8sClient$1.listCustomResources("devportal.kuadrant.io", "v1alpha1", "apiproducts");
|
|
931
995
|
const product = (products.items || []).find(
|
|
932
996
|
(p) => p.metadata.name.includes(spec.apiName) || p.spec?.displayName?.toLowerCase().includes(spec.apiName.toLowerCase())
|
|
933
997
|
);
|
|
@@ -943,7 +1007,7 @@ async function createRouter({
|
|
|
943
1007
|
if (!planLimits) {
|
|
944
1008
|
try {
|
|
945
1009
|
const policy = await k8sClient$1.getCustomResource(
|
|
946
|
-
"
|
|
1010
|
+
"devportal.kuadrant.io",
|
|
947
1011
|
"v1alpha1",
|
|
948
1012
|
spec.apiNamespace,
|
|
949
1013
|
"planpolicies",
|
|
@@ -984,10 +1048,10 @@ async function createRouter({
|
|
|
984
1048
|
planLimits
|
|
985
1049
|
};
|
|
986
1050
|
await k8sClient$1.patchCustomResourceStatus(
|
|
987
|
-
"
|
|
1051
|
+
"devportal.kuadrant.io",
|
|
988
1052
|
"v1alpha1",
|
|
989
1053
|
reqRef.namespace,
|
|
990
|
-
"
|
|
1054
|
+
"apikeys",
|
|
991
1055
|
reqRef.name,
|
|
992
1056
|
status
|
|
993
1057
|
);
|
|
@@ -1033,15 +1097,15 @@ async function createRouter({
|
|
|
1033
1097
|
for (const reqRef of requests) {
|
|
1034
1098
|
try {
|
|
1035
1099
|
const request = await k8sClient$1.getCustomResource(
|
|
1036
|
-
"
|
|
1100
|
+
"devportal.kuadrant.io",
|
|
1037
1101
|
"v1alpha1",
|
|
1038
1102
|
reqRef.namespace,
|
|
1039
|
-
"
|
|
1103
|
+
"apikeys",
|
|
1040
1104
|
reqRef.name
|
|
1041
1105
|
);
|
|
1042
1106
|
const spec = request.spec;
|
|
1043
1107
|
const apiProduct = await k8sClient$1.getCustomResource(
|
|
1044
|
-
"
|
|
1108
|
+
"devportal.kuadrant.io",
|
|
1045
1109
|
"v1alpha1",
|
|
1046
1110
|
spec.apiNamespace,
|
|
1047
1111
|
"apiproducts",
|
|
@@ -1071,10 +1135,10 @@ async function createRouter({
|
|
|
1071
1135
|
reason: comment || "rejected"
|
|
1072
1136
|
};
|
|
1073
1137
|
await k8sClient$1.patchCustomResourceStatus(
|
|
1074
|
-
"
|
|
1138
|
+
"devportal.kuadrant.io",
|
|
1075
1139
|
"v1alpha1",
|
|
1076
1140
|
reqRef.namespace,
|
|
1077
|
-
"
|
|
1141
|
+
"apikeys",
|
|
1078
1142
|
reqRef.name,
|
|
1079
1143
|
status
|
|
1080
1144
|
);
|
|
@@ -1105,10 +1169,10 @@ async function createRouter({
|
|
|
1105
1169
|
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
1106
1170
|
const { namespace, name } = req.params;
|
|
1107
1171
|
const request = await k8sClient$1.getCustomResource(
|
|
1108
|
-
"
|
|
1172
|
+
"devportal.kuadrant.io",
|
|
1109
1173
|
"v1alpha1",
|
|
1110
1174
|
namespace,
|
|
1111
|
-
"
|
|
1175
|
+
"apikeys",
|
|
1112
1176
|
name
|
|
1113
1177
|
);
|
|
1114
1178
|
const requestUserId = request.spec?.requestedBy?.userId;
|
|
@@ -1147,10 +1211,10 @@ async function createRouter({
|
|
|
1147
1211
|
}
|
|
1148
1212
|
}
|
|
1149
1213
|
await k8sClient$1.deleteCustomResource(
|
|
1150
|
-
"
|
|
1214
|
+
"devportal.kuadrant.io",
|
|
1151
1215
|
"v1alpha1",
|
|
1152
1216
|
namespace,
|
|
1153
|
-
"
|
|
1217
|
+
"apikeys",
|
|
1154
1218
|
name
|
|
1155
1219
|
);
|
|
1156
1220
|
res.status(204).send();
|
|
@@ -1179,10 +1243,10 @@ async function createRouter({
|
|
|
1179
1243
|
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
1180
1244
|
const { namespace, name } = req.params;
|
|
1181
1245
|
const existing = await k8sClient$1.getCustomResource(
|
|
1182
|
-
"
|
|
1246
|
+
"devportal.kuadrant.io",
|
|
1183
1247
|
"v1alpha1",
|
|
1184
1248
|
namespace,
|
|
1185
|
-
"
|
|
1249
|
+
"apikeys",
|
|
1186
1250
|
name
|
|
1187
1251
|
);
|
|
1188
1252
|
const requestUserId = existing.spec?.requestedBy?.userId;
|
|
@@ -1207,10 +1271,10 @@ async function createRouter({
|
|
|
1207
1271
|
}
|
|
1208
1272
|
}
|
|
1209
1273
|
const updated = await k8sClient$1.patchCustomResource(
|
|
1210
|
-
"
|
|
1274
|
+
"devportal.kuadrant.io",
|
|
1211
1275
|
"v1alpha1",
|
|
1212
1276
|
namespace,
|
|
1213
|
-
"
|
|
1277
|
+
"apikeys",
|
|
1214
1278
|
name,
|
|
1215
1279
|
parsed.data
|
|
1216
1280
|
);
|
package/dist/router.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.cjs.js","sources":["../src/router.ts"],"sourcesContent":["import { HttpAuthService, RootConfigService, UserInfoService, PermissionsService } from '@backstage/backend-plugin-api';\nimport { InputError, NotAllowedError } from '@backstage/errors';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';\nimport { z } from 'zod';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport cors from 'cors';\nimport { randomBytes } from 'crypto';\nimport { KuadrantK8sClient } from './k8s-client';\nimport { getAPIProductEntityProvider } from './module';\nimport {\n kuadrantPermissions,\n kuadrantPlanPolicyListPermission,\n kuadrantPlanPolicyReadPermission,\n kuadrantApiProductListPermission,\n kuadrantApiProductReadOwnPermission,\n kuadrantApiProductReadAllPermission,\n kuadrantApiProductCreatePermission,\n kuadrantApiProductUpdateOwnPermission,\n kuadrantApiProductUpdateAllPermission,\n kuadrantApiProductDeleteOwnPermission,\n kuadrantApiProductDeleteAllPermission,\n kuadrantApiKeyRequestCreatePermission,\n kuadrantApiKeyRequestReadOwnPermission,\n kuadrantApiKeyRequestReadAllPermission,\n kuadrantApiKeyRequestUpdateOwnPermission,\n kuadrantApiKeyRequestUpdateAllPermission,\n kuadrantApiKeyRequestDeleteOwnPermission,\n kuadrantApiKeyRequestDeleteAllPermission,\n} from './permissions';\n\nfunction generateApiKey(): string {\n return randomBytes(32).toString('hex');\n}\n\n/**\n * Extract a kubernetes-safe name from entity ref\n * e.g., \"user:default/alice\" -> \"alice\"\n * e.g., \"group:platform/api-owners\" -> \"api-owners\"\n */\nfunction extractNameFromEntityRef(entityRef: string): string {\n const parts = entityRef.split('/');\n return parts[parts.length - 1];\n}\n\nasync function getUserIdentity(req: express.Request, httpAuth: HttpAuthService, userInfo: UserInfoService): Promise<{\n userEntityRef: string;\n groups: string[];\n}> {\n const credentials = await httpAuth.credentials(req);\n\n if (!credentials || !credentials.principal) {\n throw new NotAllowedError('authentication required');\n }\n\n // get user info from credentials\n const info = await userInfo.getUserInfo(credentials);\n const groups = info.ownershipEntityRefs || [];\n\n console.log(`user identity resolved: userEntityRef=${info.userEntityRef}, groups=${groups.join(',')}`);\n return {\n userEntityRef: info.userEntityRef,\n groups\n };\n}\n\nexport async function createRouter({\n httpAuth,\n userInfo,\n config,\n permissions,\n}: {\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n config: RootConfigService;\n permissions: PermissionsService;\n}): Promise<express.Router> {\n const router = Router();\n\n // enable cors for dev mode (allows frontend on :3000 to call backend on :7007)\n router.use(cors({\n origin: 'http://localhost:3000',\n credentials: true,\n }));\n\n router.use(express.json());\n\n const k8sClient = new KuadrantK8sClient(config);\n\n // apiproduct endpoints\n router.get('/apiproducts', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const listDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductListPermission }],\n { credentials }\n );\n\n if (listDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const data = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'apiproducts');\n\n // check if user has read all permission\n const readAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductReadAllPermission }],\n { credentials }\n );\n\n if (readAllDecision[0].result === AuthorizeResult.ALLOW) {\n // admin - return all apiproducts\n res.json(data);\n } else {\n // owner - check read own permission and filter\n const readOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductReadOwnPermission }],\n { credentials }\n );\n\n if (readOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // filter to only owned apiproducts\n const ownedItems = (data.items || []).filter((item: any) => {\n const owner = item.metadata?.annotations?.['backstage.io/owner'];\n return owner === userEntityRef;\n });\n\n res.json({ ...data, items: ownedItems });\n }\n } catch (error) {\n console.error('error fetching apiproducts:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch apiproducts' });\n }\n }\n });\n\n router.get('/apiproducts/:namespace/:name', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n const { namespace, name } = req.params;\n\n // try read all permission first (admin)\n const readAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductReadAllPermission }],\n { credentials }\n );\n\n if (readAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to read own permission\n const readOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductReadOwnPermission }],\n { credentials }\n );\n\n if (readOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const data = await k8sClient.getCustomResource('extensions.kuadrant.io', 'v1alpha1', namespace, 'apiproducts', name);\n const owner = data.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only read your own api products');\n }\n\n res.json(data);\n } else {\n // admin - read any apiproduct\n const data = await k8sClient.getCustomResource('extensions.kuadrant.io', 'v1alpha1', namespace, 'apiproducts', name);\n res.json(data);\n }\n } catch (error) {\n console.error('error fetching apiproduct:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch apiproduct' });\n }\n }\n });\n\n router.post('/apiproducts', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiProductCreatePermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const apiProduct = req.body;\n const targetRef = apiProduct.spec?.targetRef;\n\n if (!targetRef?.name || !targetRef?.kind || !targetRef?.namespace) {\n throw new InputError('targetRef with name, kind, and namespace is required');\n }\n\n // derive namespace from httproute - apiproduct lives in same namespace as httproute\n const namespace = targetRef.namespace;\n apiProduct.metadata.namespace = namespace;\n\n // set ownership annotation (backstage-specific metadata)\n // note: creationTimestamp is automatically set by kubernetes api server\n if (!apiProduct.metadata.annotations) {\n apiProduct.metadata.annotations = {};\n }\n apiProduct.metadata.annotations['backstage.io/owner'] = userEntityRef;\n\n // temporary: populate plans from planpolicy until controller implements this\n // look up httproute and find planpolicy targeting it\n const httpRouteNamespace = namespace;\n const httpRouteName = targetRef.name;\n\n try {\n // list all planpolicies in the httproute's namespace\n const planPoliciesResponse = await k8sClient.listCustomResources(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n 'planpolicies',\n httpRouteNamespace\n );\n\n // find planpolicy targeting this httproute\n const planPolicy = (planPoliciesResponse.items || []).find((pp: any) => {\n const ref = pp.spec?.targetRef;\n return ref?.kind === 'HTTPRoute' &&\n ref?.name === httpRouteName &&\n (!ref?.namespace || ref?.namespace === httpRouteNamespace);\n });\n\n if (planPolicy && planPolicy.spec?.plans) {\n // copy plans from planpolicy to apiproduct spec\n apiProduct.spec.plans = planPolicy.spec.plans.map((plan: any) => ({\n tier: plan.tier,\n description: plan.description,\n limits: plan.limits\n }));\n console.log(`copied ${apiProduct.spec.plans.length} plans from planpolicy ${planPolicy.metadata.name}`);\n } else {\n console.log(`no planpolicy found for httproute ${httpRouteNamespace}/${httpRouteName}`);\n }\n } catch (error) {\n console.warn('failed to populate plans from planpolicy:', error);\n // continue without plans rather than failing the creation\n }\n\n const created = await k8sClient.createCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n apiProduct,\n );\n\n // trigger immediate catalog sync\n const provider = getAPIProductEntityProvider();\n if (provider) {\n await provider.refresh();\n }\n\n res.status(201).json(created);\n } catch (error) {\n console.error('error creating apiproduct:', error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else if (error instanceof InputError) {\n res.status(400).json({ error: error.message });\n } else {\n // pass the detailed error message to the frontend\n res.status(500).json({ error: errorMessage });\n }\n }\n });\n\n router.delete('/apiproducts/:namespace/:name', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n const { namespace, name } = req.params;\n\n // try delete all permission first (admin)\n const deleteAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductDeleteAllPermission }],\n { credentials }\n );\n\n if (deleteAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to delete own permission\n const deleteOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductDeleteOwnPermission }],\n { credentials }\n );\n\n if (deleteOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership before deleting\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const existing = await k8sClient.getCustomResource('extensions.kuadrant.io', 'v1alpha1', namespace, 'apiproducts', name);\n const owner = existing.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only delete your own api products');\n }\n }\n\n await k8sClient.deleteCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n name\n );\n\n // trigger immediate catalog sync\n const provider = getAPIProductEntityProvider();\n if (provider) {\n await provider.refresh();\n }\n\n res.status(204).send();\n } catch (error) {\n console.error('error deleting apiproduct:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to delete apiproduct' });\n }\n }\n });\n\n // httproute endpoints\n router.get('/httproutes', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiProductListPermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const data = await k8sClient.listCustomResources('gateway.networking.k8s.io', 'v1', 'httproutes');\n\n res.json(data);\n } catch (error) {\n console.error('error fetching httproutes:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch httproutes' });\n }\n }\n });\n\n router.patch('/apiproducts/:namespace/:name', async (req, res) => {\n // whitelist allowed fields for patching\n const patchSchema = z.object({\n spec: z.object({\n displayName: z.string().optional(),\n description: z.string().optional(),\n version: z.string().optional(),\n publishStatus: z.enum(['Draft', 'Published']).optional(),\n approvalMode: z.enum(['automatic', 'manual']).optional(),\n tags: z.array(z.string()).optional(),\n contact: z.object({\n email: z.string().optional(),\n team: z.string().optional(),\n slack: z.string().optional(),\n }).partial().optional(),\n documentation: z.object({\n docsURL: z.string().optional(),\n openAPISpec: z.string().optional(),\n }).partial().optional(),\n }).partial(),\n });\n\n const parsed = patchSchema.safeParse(req.body);\n if (!parsed.success) {\n return res.status(400).json({ error: 'invalid patch: ' + parsed.error.toString() });\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n\n if (!credentials || !credentials.principal) {\n throw new NotAllowedError('authentication required');\n }\n\n const { namespace, name } = req.params;\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateAllPermission }],\n { credentials }\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateOwnPermission }],\n { credentials }\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const existing = await k8sClient.getCustomResource('extensions.kuadrant.io', 'v1alpha1', namespace, 'apiproducts', name);\n const owner = existing.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only update your own api products');\n }\n }\n\n // prevent modification of ownership annotation\n if (req.body.metadata?.annotations) {\n delete req.body.metadata.annotations['backstage.io/owner'];\n }\n\n const updated = await k8sClient.patchCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n name,\n parsed.data,\n );\n\n return res.json(updated);\n } catch (error) {\n console.error('error updating apiproduct:', error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (error instanceof NotAllowedError) {\n return res.status(403).json({ error: error.message });\n } else if (error instanceof InputError) {\n return res.status(400).json({ error: error.message });\n } else {\n return res.status(500).json({ error: errorMessage });\n }\n }\n });\n\n // planpolicy endpoints\n router.get('/planpolicies', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantPlanPolicyListPermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const data = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'planpolicies');\n\n // only expose minimal info needed for UI association\n const filtered = {\n items: (data.items || []).map((policy: any) => ({\n metadata: {\n name: policy.metadata.name,\n namespace: policy.metadata.namespace,\n },\n // only expose targetRef to allow UI to match PlanPolicy -> HTTPRoute\n targetRef: policy.spec?.targetRef ? {\n kind: policy.spec.targetRef.kind,\n name: policy.spec.targetRef.name,\n namespace: policy.spec.targetRef.namespace,\n } : undefined,\n // only expose plan tier info, no other spec details\n plans: (policy.spec?.plans || []).map((plan: any) => ({\n tier: plan.tier,\n description: plan.description,\n limits: plan.limits,\n })),\n })),\n };\n\n res.json(filtered);\n } catch (error) {\n console.error('error fetching planpolicies:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch planpolicies' });\n }\n }\n });\n\n router.get('/planpolicies/:namespace/:name', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantPlanPolicyReadPermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { namespace, name } = req.params;\n const data = await k8sClient.getCustomResource('extensions.kuadrant.io', 'v1alpha1', namespace, 'planpolicies', name);\n res.json(data);\n } catch (error) {\n console.error('error fetching planpolicy:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch planpolicy' });\n }\n }\n });\n\n // apikeyrequest crud endpoints\n const requestSchema = z.object({\n apiName: z.string(),\n apiNamespace: z.string(),\n planTier: z.string(),\n useCase: z.string().optional(),\n userEmail: z.string().optional(),\n });\n\n router.post('/requests', async (req, res) => {\n const parsed = requestSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { apiName, apiNamespace, planTier, useCase, userEmail } = parsed.data;\n\n // extract userId from authenticated credentials, not from request body\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n // check permission with resource reference (per-apiproduct access control)\n const resourceRef = `apiproduct:${apiNamespace}/${apiName}`;\n const decision = await permissions.authorize(\n [{\n permission: kuadrantApiKeyRequestCreatePermission,\n resourceRef,\n }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError(`not authorised to request access to ${apiName}`);\n }\n const timestamp = new Date().toISOString();\n const randomSuffix = randomBytes(4).toString('hex');\n const userName = extractNameFromEntityRef(userEntityRef);\n const requestName = `${userName}-${apiName}-${randomSuffix}`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\n const requestedBy: any = { userId: userEntityRef };\n if (userEmail) {\n requestedBy.email = userEmail;\n }\n\n const request = {\n apiVersion: 'extensions.kuadrant.io/v1alpha1',\n kind: 'APIKeyRequest',\n metadata: {\n name: requestName,\n namespace: apiNamespace,\n },\n spec: {\n apiName,\n apiNamespace,\n planTier,\n useCase: useCase || '',\n requestedBy,\n requestedAt: timestamp,\n },\n };\n\n const created = await k8sClient.createCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n apiNamespace,\n 'apikeyrequests',\n request,\n );\n\n // check if apiproduct has automatic approval mode\n try {\n const apiProduct = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n apiNamespace,\n 'apiproducts',\n apiName,\n );\n\n if (apiProduct.spec?.approvalMode === 'automatic') {\n // automatically approve and create secret\n const apiKey = generateApiKey();\n const timestamp = Date.now();\n const userName = extractNameFromEntityRef(userEntityRef);\n const secretName = `${userName}-${apiName}-${timestamp}`\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-');\n\n const secret = {\n apiVersion: 'v1',\n kind: 'Secret',\n metadata: {\n name: secretName,\n namespace: apiNamespace,\n labels: {\n app: apiName,\n },\n annotations: {\n 'secret.kuadrant.io/plan-id': planTier,\n 'secret.kuadrant.io/user-id': userEntityRef,\n },\n },\n stringData: {\n api_key: apiKey,\n },\n type: 'Opaque',\n };\n\n await k8sClient.createSecret(apiNamespace, secret);\n\n // get plan limits\n let planLimits: any = null;\n const plan = apiProduct.spec?.plans?.find((p: any) => p.tier === planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n\n // fetch httproute to get hostname\n let apiHostname = `${apiName}.apps.example.com`;\n try {\n const httproute = await k8sClient.getCustomResource(\n 'gateway.networking.k8s.io',\n 'v1',\n apiNamespace,\n 'httproutes',\n apiName,\n );\n if (httproute.spec?.hostnames && httproute.spec.hostnames.length > 0) {\n apiHostname = httproute.spec.hostnames[0];\n }\n } catch (error) {\n console.warn('could not fetch httproute for hostname, using default:', error);\n }\n\n // update request status to approved\n const status = {\n phase: 'Approved',\n reviewedBy: 'system',\n reviewedAt: new Date().toISOString(),\n reason: 'automatic approval',\n apiKey,\n apiHostname,\n apiBasePath: '/api/v1',\n apiDescription: `${apiName} api`,\n planLimits,\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n apiNamespace,\n 'apikeyrequests',\n requestName,\n status,\n );\n }\n } catch (error) {\n console.warn('could not check approval mode or auto-approve:', error);\n // continue anyway - request was created successfully\n }\n\n res.status(201).json(created);\n } catch (error) {\n console.error('error creating api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to create api key request' });\n }\n }\n });\n\n router.get('/requests', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n // check if user can read all requests or only own\n const readAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestReadAllPermission }],\n { credentials }\n );\n\n const canReadAll = readAllDecision[0].result === AuthorizeResult.ALLOW;\n\n if (!canReadAll) {\n // try read own permission\n const readOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestReadOwnPermission }],\n { credentials }\n );\n\n if (readOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n }\n\n const status = req.query.status as string;\n const namespace = req.query.namespace as string;\n\n let data;\n if (namespace) {\n data = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'apikeyrequests', namespace);\n } else {\n data = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'apikeyrequests');\n }\n\n let filteredItems = data.items || [];\n\n // if user only has read.own permission, filter by api product ownership\n if (!canReadAll) {\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n // get all apiproducts owned by this user\n const apiproducts = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'apiproducts');\n const ownedApiProducts = (apiproducts.items || [])\n .filter((product: any) => {\n const owner = product.metadata?.annotations?.['backstage.io/owner'];\n return owner === userEntityRef;\n })\n .map((product: any) => product.metadata.name);\n\n // filter requests to only those for owned api products\n filteredItems = filteredItems.filter((req: any) =>\n ownedApiProducts.includes(req.spec?.apiName)\n );\n }\n\n if (status) {\n filteredItems = filteredItems.filter((req: any) => {\n const phase = req.status?.phase || 'Pending';\n return phase === status;\n });\n }\n\n res.json({ items: filteredItems });\n } catch (error) {\n console.error('error fetching api key requests:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch api key requests' });\n }\n }\n });\n\n router.get('/requests/my', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestReadOwnPermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // extract userId from authenticated credentials, not from query params\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const namespace = req.query.namespace as string;\n\n let data;\n if (namespace) {\n data = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'apikeyrequests', namespace);\n } else {\n data = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'apikeyrequests');\n }\n\n const filteredItems = (data.items || []).filter(\n (req: any) => req.spec?.requestedBy?.userId === userEntityRef\n );\n\n res.json({ items: filteredItems });\n } catch (error) {\n console.error('error fetching user api key requests:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch user api key requests' });\n }\n }\n });\n\n const approveRejectSchema = z.object({\n comment: z.string().optional(),\n });\n\n router.post('/requests/:namespace/:name/approve', async (req, res) => {\n const parsed = approveRejectSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n const { namespace, name } = req.params;\n const { comment } = parsed.data;\n const reviewedBy = userEntityRef;\n\n const request = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n name,\n );\n\n const spec = request.spec as any;\n\n // verify user owns/admins the apiproduct this request is for\n const apiProduct = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'apiproducts',\n spec.apiName,\n );\n\n const owner = apiProduct.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials },\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateOwnPermission }],\n { credentials },\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership of the apiproduct\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only approve requests for your own api products');\n }\n }\n const apiKey = generateApiKey();\n const timestamp = Date.now();\n const userName = extractNameFromEntityRef(spec.requestedBy.userId);\n const secretName = `${userName}-${spec.apiName}-${timestamp}`\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-');\n\n const secret = {\n apiVersion: 'v1',\n kind: 'Secret',\n metadata: {\n name: secretName,\n namespace: spec.apiNamespace,\n labels: {\n app: spec.apiName,\n },\n annotations: {\n 'secret.kuadrant.io/plan-id': spec.planTier,\n 'secret.kuadrant.io/user-id': spec.requestedBy.userId,\n },\n },\n stringData: {\n api_key: apiKey,\n },\n type: 'Opaque',\n };\n\n await k8sClient.createSecret(spec.apiNamespace, secret);\n\n // try to get plan limits from apiproduct or planpolicy\n let planLimits: any = null;\n try {\n const products = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'apiproducts');\n const product = (products.items || []).find((p: any) =>\n p.metadata.name.includes(spec.apiName) || p.spec?.displayName?.toLowerCase().includes(spec.apiName.toLowerCase())\n );\n if (product) {\n const plan = product.spec?.plans?.find((p: any) => p.tier === spec.planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n }\n } catch (e) {\n console.warn('could not fetch apiproduct for plan limits:', e);\n }\n\n if (!planLimits) {\n try {\n const policy = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'planpolicies',\n `${spec.apiName}-plan`,\n );\n const plan = policy.spec?.plans?.find((p: any) => p.tier === spec.planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n } catch (e) {\n console.warn('could not fetch planpolicy for plan limits:', e);\n }\n }\n\n // fetch httproute to get hostname\n let apiHostname = `${spec.apiName}.apps.example.com`;\n try {\n const httproute = await k8sClient.getCustomResource(\n 'gateway.networking.k8s.io',\n 'v1',\n spec.apiNamespace,\n 'httproutes',\n spec.apiName,\n );\n if (httproute.spec?.hostnames && httproute.spec.hostnames.length > 0) {\n apiHostname = httproute.spec.hostnames[0];\n }\n } catch (error) {\n console.warn('could not fetch httproute for hostname, using default:', error);\n }\n\n const status = {\n phase: 'Approved',\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n reason: comment || 'approved',\n apiKey,\n apiHostname,\n apiBasePath: '/api/v1',\n apiDescription: `${spec.apiName} api`,\n planLimits,\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n name,\n status,\n );\n\n res.json({ secretName });\n } catch (error) {\n console.error('error approving api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to approve api key request' });\n }\n }\n });\n\n router.post('/requests/:namespace/:name/reject', async (req, res) => {\n const parsed = approveRejectSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n const { namespace, name } = req.params;\n const { comment } = parsed.data;\n const reviewedBy = userEntityRef;\n\n // fetch request to get apiproduct info\n const request = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n name,\n );\n\n const spec = request.spec as any;\n\n // verify user owns/admins the apiproduct this request is for\n const apiProduct = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'apiproducts',\n spec.apiName,\n );\n\n const owner = apiProduct.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials },\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateOwnPermission }],\n { credentials },\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership of the apiproduct\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only reject requests for your own api products');\n }\n }\n\n const status = {\n phase: 'Rejected',\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n reason: comment || 'rejected',\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n name,\n status,\n );\n\n res.status(204).send();\n } catch (error) {\n console.error('error rejecting api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to reject api key request' });\n }\n }\n });\n\n const bulkApproveSchema = z.object({\n requests: z.array(z.object({\n namespace: z.string(),\n name: z.string(),\n })),\n comment: z.string().optional(),\n });\n\n router.post('/requests/bulk-approve', async (req, res) => {\n const parsed = bulkApproveSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials },\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { requests, comment } = parsed.data;\n const reviewedBy = userEntityRef;\n const results = [];\n\n for (const reqRef of requests) {\n try {\n const request = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n reqRef.namespace,\n 'apikeyrequests',\n reqRef.name,\n );\n\n const spec = request.spec as any;\n\n // verify user owns/admins the apiproduct this request is for\n const apiProduct = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'apiproducts',\n spec.apiName,\n );\n\n const owner = apiProduct.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateAllPermission }],\n { credentials },\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateOwnPermission }],\n { credentials },\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership of the apiproduct\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only approve requests for your own api products');\n }\n }\n const apiKey = generateApiKey();\n const timestamp = Date.now();\n const userName = extractNameFromEntityRef(spec.requestedBy.userId);\n const secretName = `${userName}-${spec.apiName}-${timestamp}`\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-');\n\n const secret = {\n apiVersion: 'v1',\n kind: 'Secret',\n metadata: {\n name: secretName,\n namespace: spec.apiNamespace,\n labels: {\n app: spec.apiName,\n },\n annotations: {\n 'secret.kuadrant.io/plan-id': spec.planTier,\n 'secret.kuadrant.io/user-id': spec.requestedBy.userId,\n },\n },\n stringData: {\n api_key: apiKey,\n },\n type: 'Opaque',\n };\n\n await k8sClient.createSecret(spec.apiNamespace, secret);\n\n // try to get plan limits from apiproduct or planpolicy\n let planLimits: any = null;\n try {\n const products = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'apiproducts');\n const product = (products.items || []).find((p: any) =>\n p.metadata.name.includes(spec.apiName) || p.spec?.displayName?.toLowerCase().includes(spec.apiName.toLowerCase())\n );\n if (product) {\n const plan = product.spec?.plans?.find((p: any) => p.tier === spec.planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n }\n } catch (e) {\n console.warn('could not fetch apiproduct for plan limits:', e);\n }\n\n if (!planLimits) {\n try {\n const policy = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'planpolicies',\n `${spec.apiName}-plan`,\n );\n const plan = policy.spec?.plans?.find((p: any) => p.tier === spec.planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n } catch (e) {\n console.warn('could not fetch planpolicy for plan limits:', e);\n }\n }\n\n // fetch httproute to get hostname\n let apiHostname = `${spec.apiName}.apps.example.com`;\n try {\n const httproute = await k8sClient.getCustomResource(\n 'gateway.networking.k8s.io',\n 'v1',\n spec.apiNamespace,\n 'httproutes',\n spec.apiName,\n );\n if (httproute.spec?.hostnames && httproute.spec.hostnames.length > 0) {\n apiHostname = httproute.spec.hostnames[0];\n }\n } catch (error) {\n console.warn('could not fetch httproute for hostname, using default:', error);\n }\n\n const status = {\n phase: 'Approved',\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n reason: comment || 'approved',\n apiKey,\n apiHostname,\n apiBasePath: '/api/v1',\n apiDescription: `${spec.apiName} api`,\n planLimits,\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n reqRef.namespace,\n 'apikeyrequests',\n reqRef.name,\n status,\n );\n\n results.push({ namespace: reqRef.namespace, name: reqRef.name, success: true, secretName });\n } catch (error) {\n console.error(`error approving request ${reqRef.namespace}/${reqRef.name}:`, error);\n results.push({\n namespace: reqRef.namespace,\n name: reqRef.name,\n success: false,\n error: error instanceof Error ? error.message : 'unknown error'\n });\n }\n }\n\n res.json({ results });\n } catch (error) {\n console.error('error in bulk approve:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to bulk approve api key requests' });\n }\n }\n });\n\n router.post('/requests/bulk-reject', async (req, res) => {\n const parsed = bulkApproveSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials },\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { requests, comment } = parsed.data;\n const reviewedBy = userEntityRef;\n const results = [];\n\n for (const reqRef of requests) {\n try {\n // fetch request to get apiproduct info\n const request = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n reqRef.namespace,\n 'apikeyrequests',\n reqRef.name,\n );\n\n const spec = request.spec as any;\n\n // verify user owns/admins the apiproduct this request is for\n const apiProduct = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'apiproducts',\n spec.apiName,\n );\n\n const owner = apiProduct.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateAllPermission }],\n { credentials },\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateOwnPermission }],\n { credentials },\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership of the apiproduct\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only reject requests for your own api products');\n }\n }\n\n const status = {\n phase: 'Rejected',\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n reason: comment || 'rejected',\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n reqRef.namespace,\n 'apikeyrequests',\n reqRef.name,\n status,\n );\n\n results.push({ namespace: reqRef.namespace, name: reqRef.name, success: true });\n } catch (error) {\n console.error(`error rejecting request ${reqRef.namespace}/${reqRef.name}:`, error);\n results.push({\n namespace: reqRef.namespace,\n name: reqRef.name,\n success: false,\n error: error instanceof Error ? error.message : 'unknown error'\n });\n }\n }\n\n res.json({ results });\n } catch (error) {\n console.error('error in bulk reject:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to bulk reject api key requests' });\n }\n }\n });\n\n router.delete('/requests/:namespace/:name', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const { namespace, name } = req.params;\n\n // get request to verify ownership\n const request = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n name,\n );\n\n const requestUserId = request.spec?.requestedBy?.userId;\n\n // check if user can delete all requests or just their own\n const deleteAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestDeleteAllPermission }],\n { credentials }\n );\n\n const canDeleteAll = deleteAllDecision[0].result === AuthorizeResult.ALLOW;\n\n if (!canDeleteAll) {\n // check if user can delete their own requests\n const deleteOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestDeleteOwnPermission }],\n { credentials }\n );\n\n if (deleteOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership\n if (requestUserId !== userEntityRef) {\n throw new NotAllowedError('you can only delete your own api key requests');\n }\n }\n\n // if request is approved, find and delete associated secret\n if (request.status?.phase === 'Approved') {\n try {\n const apiNamespace = request.spec?.apiNamespace;\n const apiName = request.spec?.apiName;\n const planTier = request.spec?.planTier;\n\n // list secrets in the api namespace and find the one with matching annotations\n const secrets = await k8sClient.listSecrets(apiNamespace);\n const matchingSecret = secrets.items?.find((s: any) => {\n const annotations = s.metadata?.annotations || {};\n return (\n annotations['secret.kuadrant.io/user-id'] === requestUserId &&\n annotations['secret.kuadrant.io/plan-id'] === planTier &&\n s.metadata?.labels?.app === apiName\n );\n });\n\n if (matchingSecret) {\n await k8sClient.deleteSecret(apiNamespace, matchingSecret.metadata.name);\n }\n } catch (error) {\n console.warn('failed to delete associated secret:', error);\n // continue with request deletion even if secret deletion fails\n }\n }\n\n await k8sClient.deleteCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n name,\n );\n res.status(204).send();\n } catch (error) {\n console.error('error deleting api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to delete api key request' });\n }\n }\n });\n\n router.patch('/requests/:namespace/:name', async (req, res) => {\n // whitelist allowed fields for patching\n const patchSchema = z.object({\n spec: z.object({\n useCase: z.string().optional(),\n planTier: z.string().optional(),\n }).partial(),\n });\n\n const parsed = patchSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError('invalid patch: ' + parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const { namespace, name } = req.params;\n\n // get existing request to check ownership and status\n const existing = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n name,\n );\n\n const requestUserId = existing.spec?.requestedBy?.userId;\n const currentPhase = existing.status?.phase || 'Pending';\n\n // only pending requests can be edited\n if (currentPhase !== 'Pending') {\n throw new NotAllowedError('only pending requests can be edited');\n }\n\n // check if user can update all requests or just their own\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials }\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // check if user can update their own requests\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateOwnPermission }],\n { credentials }\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership\n if (requestUserId !== userEntityRef) {\n throw new NotAllowedError('you can only update your own api key requests');\n }\n }\n\n // apply validated patch\n const updated = await k8sClient.patchCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n name,\n parsed.data,\n );\n\n res.json(updated);\n } catch (error) {\n console.error('error updating api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else if (error instanceof InputError) {\n res.status(400).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to update api key request' });\n }\n }\n });\n\n // expose permissions for backstage permission framework\n router.use(createPermissionIntegrationRouter({\n permissions: kuadrantPermissions,\n }));\n\n return router;\n}\n"],"names":["randomBytes","NotAllowedError","permissions","Router","cors","express","k8sClient","KuadrantK8sClient","kuadrantApiProductListPermission","AuthorizeResult","kuadrantApiProductReadAllPermission","kuadrantApiProductReadOwnPermission","kuadrantApiProductCreatePermission","InputError","getAPIProductEntityProvider","kuadrantApiProductDeleteAllPermission","kuadrantApiProductDeleteOwnPermission","z","kuadrantApiProductUpdateAllPermission","kuadrantApiProductUpdateOwnPermission","kuadrantPlanPolicyListPermission","kuadrantPlanPolicyReadPermission","kuadrantApiKeyRequestCreatePermission","timestamp","userName","kuadrantApiKeyRequestReadAllPermission","kuadrantApiKeyRequestReadOwnPermission","req","kuadrantApiKeyRequestUpdateAllPermission","kuadrantApiKeyRequestUpdateOwnPermission","kuadrantApiKeyRequestDeleteAllPermission","kuadrantApiKeyRequestDeleteOwnPermission","createPermissionIntegrationRouter","kuadrantPermissions"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../src/router.ts"],"sourcesContent":["import { HttpAuthService, RootConfigService, UserInfoService, PermissionsService } from '@backstage/backend-plugin-api';\nimport { InputError, NotAllowedError } from '@backstage/errors';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\nimport { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';\nimport { z } from 'zod';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport cors from 'cors';\nimport { randomBytes } from 'crypto';\nimport { KuadrantK8sClient } from './k8s-client';\nimport { getAPIProductEntityProvider } from './module';\nimport {\n kuadrantPermissions,\n kuadrantPlanPolicyListPermission,\n kuadrantPlanPolicyReadPermission,\n kuadrantApiProductListPermission,\n kuadrantApiProductReadOwnPermission,\n kuadrantApiProductReadAllPermission,\n kuadrantApiProductCreatePermission,\n kuadrantApiProductUpdateOwnPermission,\n kuadrantApiProductUpdateAllPermission,\n kuadrantApiProductDeleteOwnPermission,\n kuadrantApiProductDeleteAllPermission,\n kuadrantApiKeyRequestCreatePermission,\n kuadrantApiKeyRequestReadOwnPermission,\n kuadrantApiKeyRequestReadAllPermission,\n kuadrantApiKeyRequestUpdateOwnPermission,\n kuadrantApiKeyRequestUpdateAllPermission,\n kuadrantApiKeyRequestDeleteOwnPermission,\n kuadrantApiKeyRequestDeleteAllPermission,\n} from './permissions';\n\nfunction generateApiKey(): string {\n return randomBytes(32).toString('hex');\n}\n\n/**\n * Extract a kubernetes-safe name from entity ref\n * e.g., \"user:default/alice\" -> \"alice\"\n * e.g., \"group:platform/api-owners\" -> \"api-owners\"\n */\nfunction extractNameFromEntityRef(entityRef: string): string {\n const parts = entityRef.split('/');\n return parts[parts.length - 1];\n}\n\nasync function getUserIdentity(req: express.Request, httpAuth: HttpAuthService, userInfo: UserInfoService): Promise<{\n userEntityRef: string;\n groups: string[];\n}> {\n const credentials = await httpAuth.credentials(req);\n\n if (!credentials || !credentials.principal) {\n throw new NotAllowedError('authentication required');\n }\n\n // get user info from credentials\n const info = await userInfo.getUserInfo(credentials);\n const groups = info.ownershipEntityRefs || [];\n\n console.log(`user identity resolved: userEntityRef=${info.userEntityRef}, groups=${groups.join(',')}`);\n return {\n userEntityRef: info.userEntityRef,\n groups\n };\n}\n\nexport async function createRouter({\n httpAuth,\n userInfo,\n config,\n permissions,\n}: {\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n config: RootConfigService;\n permissions: PermissionsService;\n}): Promise<express.Router> {\n const router = Router();\n\n // enable cors for dev mode (allows frontend on :3000 to call backend on :7007)\n router.use(cors({\n origin: 'http://localhost:3000',\n credentials: true,\n }));\n\n router.use(express.json());\n\n const k8sClient = new KuadrantK8sClient(config);\n\n // apiproduct endpoints\n router.get('/apiproducts', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const listDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductListPermission }],\n { credentials }\n );\n\n if (listDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const data = await k8sClient.listCustomResources('devportal.kuadrant.io', 'v1alpha1', 'apiproducts');\n\n // check if user has read all permission\n const readAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductReadAllPermission }],\n { credentials }\n );\n\n if (readAllDecision[0].result === AuthorizeResult.ALLOW) {\n // admin - return all apiproducts\n res.json(data);\n } else {\n // owner - check read own permission and filter\n const readOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductReadOwnPermission }],\n { credentials }\n );\n\n if (readOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // filter to only owned apiproducts\n const ownedItems = (data.items || []).filter((item: any) => {\n const owner = item.metadata?.annotations?.['backstage.io/owner'];\n return owner === userEntityRef;\n });\n\n res.json({ ...data, items: ownedItems });\n }\n } catch (error) {\n console.error('error fetching apiproducts:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch apiproducts' });\n }\n }\n });\n\n router.get('/apiproducts/:namespace/:name', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n const { namespace, name } = req.params;\n\n // try read all permission first (admin)\n const readAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductReadAllPermission }],\n { credentials }\n );\n\n if (readAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to read own permission\n const readOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductReadOwnPermission }],\n { credentials }\n );\n\n if (readOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const data = await k8sClient.getCustomResource('devportal.kuadrant.io', 'v1alpha1', namespace, 'apiproducts', name);\n const owner = data.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only read your own api products');\n }\n\n res.json(data);\n } else {\n // admin - read any apiproduct\n const data = await k8sClient.getCustomResource('devportal.kuadrant.io', 'v1alpha1', namespace, 'apiproducts', name);\n res.json(data);\n }\n } catch (error) {\n console.error('error fetching apiproduct:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch apiproduct' });\n }\n }\n });\n\n router.post('/apiproducts', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiProductCreatePermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const apiProduct = req.body;\n const targetRef = apiProduct.spec?.targetRef;\n\n if (!targetRef?.name || !targetRef?.kind || !targetRef?.namespace) {\n throw new InputError('targetRef with name, kind, and namespace is required');\n }\n\n // derive namespace from httproute - apiproduct lives in same namespace as httproute\n const namespace = targetRef.namespace;\n apiProduct.metadata.namespace = namespace;\n\n // set ownership annotation (backstage-specific metadata)\n // note: creationTimestamp is automatically set by kubernetes api server\n if (!apiProduct.metadata.annotations) {\n apiProduct.metadata.annotations = {};\n }\n apiProduct.metadata.annotations['backstage.io/owner'] = userEntityRef;\n\n // temporary: populate plans from planpolicy until controller implements this\n // look up httproute and find planpolicy targeting it\n const httpRouteNamespace = namespace;\n const httpRouteName = targetRef.name;\n\n try {\n // list all planpolicies in the httproute's namespace\n const planPoliciesResponse = await k8sClient.listCustomResources(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n 'planpolicies',\n httpRouteNamespace\n );\n\n // find planpolicy targeting this httproute\n const planPolicy = (planPoliciesResponse.items || []).find((pp: any) => {\n const ref = pp.spec?.targetRef;\n return ref?.kind === 'HTTPRoute' &&\n ref?.name === httpRouteName &&\n (!ref?.namespace || ref?.namespace === httpRouteNamespace);\n });\n\n if (planPolicy && planPolicy.spec?.plans) {\n // copy plans from planpolicy to apiproduct spec\n apiProduct.spec.plans = planPolicy.spec.plans.map((plan: any) => ({\n tier: plan.tier,\n description: plan.description,\n limits: plan.limits\n }));\n console.log(`copied ${apiProduct.spec.plans.length} plans from planpolicy ${planPolicy.metadata.name}`);\n } else {\n console.log(`no planpolicy found for httproute ${httpRouteNamespace}/${httpRouteName}`);\n }\n } catch (error) {\n console.warn('failed to populate plans from planpolicy:', error);\n // continue without plans rather than failing the creation\n }\n\n const created = await k8sClient.createCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n apiProduct,\n );\n\n // trigger immediate catalog sync\n const provider = getAPIProductEntityProvider();\n if (provider) {\n await provider.refresh();\n }\n\n res.status(201).json(created);\n } catch (error) {\n console.error('error creating apiproduct:', error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else if (error instanceof InputError) {\n res.status(400).json({ error: error.message });\n } else {\n // pass the detailed error message to the frontend\n res.status(500).json({ error: errorMessage });\n }\n }\n });\n\n router.delete('/apiproducts/:namespace/:name', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n const { namespace, name } = req.params;\n\n // try delete all permission first (admin)\n const deleteAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductDeleteAllPermission }],\n { credentials }\n );\n\n if (deleteAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to delete own permission\n const deleteOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductDeleteOwnPermission }],\n { credentials }\n );\n\n if (deleteOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership before deleting\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const existing = await k8sClient.getCustomResource('devportal.kuadrant.io', 'v1alpha1', namespace, 'apiproducts', name);\n const owner = existing.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only delete your own api products');\n }\n }\n console.log(`cascading delete: finding apikeyrequests for ${namespace}/${name}`);\n\n let allRequests;\n try {\n allRequests = await k8sClient.listCustomResources(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n 'apikeyrequests',\n namespace\n );\n } catch (error) {\n console.warn('failed to list apikeyrequests during cascade delete:', error);\n allRequests = { items: [] };\n }\n\n // filter requests that belong to this APIProduct\n const relatedRequests = (allRequests.items || []).filter((req: any) =>\n req.spec?.apiName === name && req.spec?.apiNamespace === namespace\n );\n\n console.log(`found ${relatedRequests.length} apikeyrequests to delete`);\n\n // delete each APIKeyRequest and its associated Secret\n const deletionResults = await Promise.allSettled(\n relatedRequests.map(async (request: any) => {\n const requestName = request.metadata.name;\n const requestUserId = request.spec?.requestedBy?.userId;\n const planTier = request.spec?.planTier;\n\n console.log(`deleting apikeyrequest: ${namespace}/${requestName}`);\n\n // iff request is approved, delete the associated secret first\n if (request.status?.phase === 'Approved') {\n try {\n console.log(`finding secret for approved request: ${namespace}/${requestName}`);\n const secrets = await k8sClient.listSecrets(namespace);\n const matchingSecret = secrets.items?.find((s: any) => {\n const annotations = s.metadata?.annotations || {};\n return (\n annotations['secret.kuadrant.io/user-id'] === requestUserId &&\n annotations['secret.kuadrant.io/plan-id'] === planTier &&\n s.metadata?.labels?.app === name\n );\n });\n\n if (matchingSecret) {\n console.log(`deleting secret: ${namespace}/${matchingSecret.metadata.name}`);\n await k8sClient.deleteSecret(namespace, matchingSecret.metadata.name);\n }\n } catch (error) {\n console.warn(`failed to delete secret for request ${requestName}:`, error);\n // continue with request deletion even if secret deletion fails\n }\n }\n\n // delete the ApiKeyRequest\n await k8sClient.deleteCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeyrequests',\n requestName\n );\n })\n );\n\n // log any failures (but don't block APIProduct deletion)\n const failures = deletionResults.filter(r => r.status === 'rejected');\n if (failures.length > 0) {\n console.warn(`${failures.length} apikeyrequests/secret failed to delete:`,\n failures.map((f: any) => f.reason)\n );\n }\n await k8sClient.deleteCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n name\n );\n\n // trigger immediate catalog sync\n const provider = getAPIProductEntityProvider();\n if (provider) {\n await provider.refresh();\n }\n\n res.status(204).send();\n } catch (error) {\n console.error('error deleting apiproduct:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to delete apiproduct' });\n }\n }\n });\n\n // httproute endpoints\n router.get('/httproutes', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiProductListPermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const data = await k8sClient.listCustomResources('gateway.networking.k8s.io', 'v1', 'httproutes');\n\n res.json(data);\n } catch (error) {\n console.error('error fetching httproutes:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch httproutes' });\n }\n }\n });\n\n router.patch('/apiproducts/:namespace/:name', async (req, res) => {\n // whitelist allowed fields for patching\n const patchSchema = z.object({\n spec: z.object({\n displayName: z.string().optional(),\n description: z.string().optional(),\n version: z.string().optional(),\n publishStatus: z.enum(['Draft', 'Published']).optional(),\n approvalMode: z.enum(['automatic', 'manual']).optional(),\n tags: z.array(z.string()).optional(),\n contact: z.object({\n email: z.string().optional(),\n team: z.string().optional(),\n slack: z.string().optional(),\n }).partial().optional(),\n documentation: z.object({\n docsURL: z.string().optional(),\n openAPISpec: z.string().optional(),\n }).partial().optional(),\n }).partial(),\n });\n\n const parsed = patchSchema.safeParse(req.body);\n if (!parsed.success) {\n return res.status(400).json({ error: 'invalid patch: ' + parsed.error.toString() });\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n\n if (!credentials || !credentials.principal) {\n throw new NotAllowedError('authentication required');\n }\n\n const { namespace, name } = req.params;\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateAllPermission }],\n { credentials }\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateOwnPermission }],\n { credentials }\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const existing = await k8sClient.getCustomResource('devportal.kuadrant.io', 'v1alpha1', namespace, 'apiproducts', name);\n const owner = existing.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only update your own api products');\n }\n }\n\n // prevent modification of ownership annotation\n if (req.body.metadata?.annotations) {\n delete req.body.metadata.annotations['backstage.io/owner'];\n }\n\n const updated = await k8sClient.patchCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n name,\n parsed.data,\n );\n\n return res.json(updated);\n } catch (error) {\n console.error('error updating apiproduct:', error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (error instanceof NotAllowedError) {\n return res.status(403).json({ error: error.message });\n } else if (error instanceof InputError) {\n return res.status(400).json({ error: error.message });\n } else {\n return res.status(500).json({ error: errorMessage });\n }\n }\n });\n\n // planpolicy endpoints\n router.get('/planpolicies', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantPlanPolicyListPermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const data = await k8sClient.listCustomResources('extensions.kuadrant.io', 'v1alpha1', 'planpolicies');\n\n // only expose minimal info needed for UI association\n const filtered = {\n items: (data.items || []).map((policy: any) => ({\n metadata: {\n name: policy.metadata.name,\n namespace: policy.metadata.namespace,\n },\n // only expose targetRef to allow UI to match PlanPolicy -> HTTPRoute\n targetRef: policy.spec?.targetRef ? {\n kind: policy.spec.targetRef.kind,\n name: policy.spec.targetRef.name,\n namespace: policy.spec.targetRef.namespace,\n } : undefined,\n // only expose plan tier info, no other spec details\n plans: (policy.spec?.plans || []).map((plan: any) => ({\n tier: plan.tier,\n description: plan.description,\n limits: plan.limits,\n })),\n })),\n };\n\n res.json(filtered);\n } catch (error) {\n console.error('error fetching planpolicies:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch planpolicies' });\n }\n }\n });\n\n router.get('/planpolicies/:namespace/:name', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantPlanPolicyReadPermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { namespace, name } = req.params;\n const data = await k8sClient.getCustomResource('extensions.kuadrant.io', 'v1alpha1', namespace, 'planpolicies', name);\n res.json(data);\n } catch (error) {\n console.error('error fetching planpolicy:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch planpolicy' });\n }\n }\n });\n\n // apikey crud endpoints\n const requestSchema = z.object({\n apiProductName: z.string(), // name of the APIProduct\n namespace: z.string(), // namespace where both APIProduct and APIKey live\n planTier: z.string(),\n useCase: z.string().optional(),\n userEmail: z.string().optional(),\n });\n\n router.post('/requests', async (req, res) => {\n const parsed = requestSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { apiProductName, namespace, planTier, useCase, userEmail } = parsed.data;\n\n // extract userId from authenticated credentials, not from request body\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n // check permission with resource reference (per-apiproduct access control)\n const resourceRef = `apiproduct:${namespace}/${apiProductName}`;\n const decision = await permissions.authorize(\n [{\n permission: kuadrantApiKeyRequestCreatePermission,\n resourceRef,\n }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError(`not authorised to request access to ${apiProductName}`);\n }\n const randomSuffix = randomBytes(4).toString('hex');\n const userName = extractNameFromEntityRef(userEntityRef);\n const requestName = `${userName}-${apiProductName}-${randomSuffix}`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n\n const requestedBy: any = { userId: userEntityRef };\n if (userEmail) {\n requestedBy.email = userEmail;\n }\n\n const request = {\n apiVersion: 'devportal.kuadrant.io/v1alpha1',\n kind: 'APIKey',\n metadata: {\n name: requestName,\n namespace,\n },\n spec: {\n apiProductRef: {\n name: apiProductName,\n },\n planTier,\n useCase: useCase || '',\n requestedBy,\n },\n };\n\n const created = await k8sClient.createCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n request,\n );\n\n // check if apiproduct has automatic approval mode\n try {\n const apiProduct = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n apiProductName,\n );\n\n if (apiProduct.spec?.approvalMode === 'automatic') {\n // automatically approve and create secret\n const apiKey = generateApiKey();\n const timestamp = Date.now();\n const userName = extractNameFromEntityRef(userEntityRef);\n const secretName = `${userName}-${apiProductName}-${timestamp}`\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-');\n\n const secret = {\n apiVersion: 'v1',\n kind: 'Secret',\n metadata: {\n name: secretName,\n namespace,\n labels: {\n app: apiProductName,\n },\n annotations: {\n 'secret.kuadrant.io/plan-id': planTier,\n 'secret.kuadrant.io/user-id': userEntityRef,\n },\n },\n stringData: {\n api_key: apiKey,\n },\n type: 'Opaque',\n };\n\n await k8sClient.createSecret(namespace, secret);\n\n // get plan limits\n let planLimits: any = null;\n const plan = apiProduct.spec?.plans?.find((p: any) => p.tier === planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n\n // fetch httproute to get hostname\n let apiHostname = `${apiProductName}.apps.example.com`;\n try {\n const httproute = await k8sClient.getCustomResource(\n 'gateway.networking.k8s.io',\n 'v1',\n namespace,\n 'httproutes',\n apiProductName,\n );\n if (httproute.spec?.hostnames && httproute.spec.hostnames.length > 0) {\n apiHostname = httproute.spec.hostnames[0];\n }\n } catch (error) {\n console.warn('could not fetch httproute for hostname, using default:', error);\n }\n\n // update request status to approved\n const status = {\n phase: 'Approved',\n reviewedBy: 'system',\n reviewedAt: new Date().toISOString(),\n reason: 'automatic approval',\n apiKey,\n apiHostname,\n apiBasePath: '/api/v1',\n apiDescription: `${apiProductName} api`,\n planLimits,\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n requestName,\n status,\n );\n }\n } catch (error) {\n console.warn('could not check approval mode or auto-approve:', error);\n // continue anyway - request was created successfully\n }\n\n res.status(201).json(created);\n } catch (error) {\n console.error('error creating api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to create api key request' });\n }\n }\n });\n\n router.get('/requests', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n // check if user can read all requests or only own\n const readAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestReadAllPermission }],\n { credentials }\n );\n\n const canReadAll = readAllDecision[0].result === AuthorizeResult.ALLOW;\n\n if (!canReadAll) {\n // try read own permission\n const readOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestReadOwnPermission }],\n { credentials }\n );\n\n if (readOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n }\n\n const status = req.query.status as string;\n const namespace = req.query.namespace as string;\n\n let data;\n if (namespace) {\n data = await k8sClient.listCustomResources('devportal.kuadrant.io', 'v1alpha1', 'aPIKeys', namespace);\n } else {\n data = await k8sClient.listCustomResources('devportal.kuadrant.io', 'v1alpha1', 'aPIKeys');\n }\n\n let filteredItems = data.items || [];\n\n // if user only has read.own permission, filter by api product ownership\n if (!canReadAll) {\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n // get all apiproducts owned by this user\n const apiproducts = await k8sClient.listCustomResources('devportal.kuadrant.io', 'v1alpha1', 'apiproducts');\n const ownedApiProducts = (apiproducts.items || [])\n .filter((product: any) => {\n const owner = product.metadata?.annotations?.['backstage.io/owner'];\n return owner === userEntityRef;\n })\n .map((product: any) => product.metadata.name);\n\n // filter requests to only those for owned api products\n filteredItems = filteredItems.filter((req: any) =>\n ownedApiProducts.includes(req.spec?.apiName)\n );\n }\n\n if (status) {\n filteredItems = filteredItems.filter((req: any) => {\n const phase = req.status?.phase || 'Pending';\n return phase === status;\n });\n }\n\n res.json({ items: filteredItems });\n } catch (error) {\n console.error('error fetching api key requests:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch api key requests' });\n }\n }\n });\n\n router.get('/requests/my', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestReadOwnPermission }],\n { credentials }\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // extract userId from authenticated credentials, not from query params\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const namespace = req.query.namespace as string;\n\n let data;\n if (namespace) {\n data = await k8sClient.listCustomResources('devportal.kuadrant.io', 'v1alpha1', 'apikeys', namespace);\n } else {\n data = await k8sClient.listCustomResources('devportal.kuadrant.io', 'v1alpha1', 'apikeys');\n }\n\n const filteredItems = (data.items || []).filter(\n (req: any) => req.spec?.requestedBy?.userId === userEntityRef\n );\n\n res.json({ items: filteredItems });\n } catch (error) {\n console.error('error fetching user api key requests:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to fetch user api key requests' });\n }\n }\n });\n\n const approveRejectSchema = z.object({\n comment: z.string().optional(),\n });\n\n router.post('/requests/:namespace/:name/approve', async (req, res) => {\n const parsed = approveRejectSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n const { namespace, name } = req.params;\n const { comment } = parsed.data;\n const reviewedBy = userEntityRef;\n\n const request = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n name,\n );\n\n const spec = request.spec as any;\n const apiProductName = spec.apiProductRef?.name;\n\n if (!apiProductName) {\n throw new InputError('apiProductRef.name is required in APIKey spec');\n }\n\n // verify user owns/admins the apiproduct this request is for\n const apiProduct = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n apiProductName,\n );\n\n const owner = apiProduct.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials },\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateOwnPermission }],\n { credentials },\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership of the apiproduct\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only approve requests for your own api products');\n }\n }\n const apiKey = generateApiKey();\n const timestamp = Date.now();\n const userName = extractNameFromEntityRef(spec.requestedBy.userId);\n const secretName = `${userName}-${apiProductName}-${timestamp}`\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-');\n\n const secret = {\n apiVersion: 'v1',\n kind: 'Secret',\n metadata: {\n name: secretName,\n namespace,\n labels: {\n app: apiProductName,\n },\n annotations: {\n 'secret.kuadrant.io/plan-id': spec.planTier,\n 'secret.kuadrant.io/user-id': spec.requestedBy.userId,\n },\n },\n stringData: {\n api_key: apiKey,\n },\n type: 'Opaque',\n };\n\n await k8sClient.createSecret(namespace, secret);\n\n // try to get plan limits from apiproduct or planpolicy\n let planLimits: any = null;\n try {\n const products = await k8sClient.listCustomResources('devportal.kuadrant.io', 'v1alpha1', 'apiproducts');\n const product = (products.items || []).find((p: any) =>\n p.metadata.name.includes(apiProductName) || p.spec?.displayName?.toLowerCase().includes(apiProductName.toLowerCase())\n );\n if (product) {\n const plan = product.spec?.plans?.find((p: any) => p.tier === spec.planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n }\n } catch (e) {\n console.warn('could not fetch apiproduct for plan limits:', e);\n }\n\n if (!planLimits) {\n try {\n const policy = await k8sClient.getCustomResource(\n 'extensions.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'planpolicies',\n `${apiProductName}-plan`,\n );\n const plan = policy.spec?.plans?.find((p: any) => p.tier === spec.planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n } catch (e) {\n console.warn('could not fetch planpolicy for plan limits:', e);\n }\n }\n\n // fetch httproute to get hostname\n let apiHostname = `${apiProductName}.apps.example.com`;\n try {\n const httproute = await k8sClient.getCustomResource(\n 'gateway.networking.k8s.io',\n 'v1',\n namespace,\n 'httproutes',\n apiProductName,\n );\n if (httproute.spec?.hostnames && httproute.spec.hostnames.length > 0) {\n apiHostname = httproute.spec.hostnames[0];\n }\n } catch (error) {\n console.warn('could not fetch httproute for hostname, using default:', error);\n }\n\n const status = {\n phase: 'Approved',\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n reason: comment || 'approved',\n apiKey,\n apiHostname,\n apiBasePath: '/api/v1',\n apiDescription: `${apiProductName} api`,\n planLimits,\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n name,\n status,\n );\n\n res.json({ secretName });\n } catch (error) {\n console.error('error approving api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to approve api key request' });\n }\n }\n });\n\n router.post('/requests/:namespace/:name/reject', async (req, res) => {\n const parsed = approveRejectSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n const { namespace, name } = req.params;\n const { comment } = parsed.data;\n const reviewedBy = userEntityRef;\n\n // fetch request to get apiproduct info\n const request = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n name,\n );\n\n const spec = request.spec as any;\n const apiProductName = spec.apiProductRef?.name;\n\n if (!apiProductName) {\n throw new InputError('apiProductRef.name is required in APIKey spec');\n }\n\n // verify user owns/admins the apiproduct this request is for\n const apiProduct = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apiproducts',\n apiProductName,\n );\n\n const owner = apiProduct.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials },\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateOwnPermission }],\n { credentials },\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership of the apiproduct\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only reject requests for your own api products');\n }\n }\n\n const status = {\n phase: 'Rejected',\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n reason: comment || 'rejected',\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n name,\n status,\n );\n\n res.status(204).send();\n } catch (error) {\n console.error('error rejecting api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to reject api key request' });\n }\n }\n });\n\n const bulkApproveSchema = z.object({\n requests: z.array(z.object({\n namespace: z.string(),\n name: z.string(),\n })),\n comment: z.string().optional(),\n });\n\n router.post('/requests/bulk-approve', async (req, res) => {\n const parsed = bulkApproveSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials },\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { requests, comment } = parsed.data;\n const reviewedBy = userEntityRef;\n const results = [];\n\n for (const reqRef of requests) {\n try {\n const request = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n reqRef.namespace,\n 'apikeys',\n reqRef.name,\n );\n\n const spec = request.spec as any;\n\n // verify user owns/admins the apiproduct this request is for\n const apiProduct = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'apiproducts',\n spec.apiName,\n );\n\n const owner = apiProduct.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateAllPermission }],\n { credentials },\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateOwnPermission }],\n { credentials },\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership of the apiproduct\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only approve requests for your own api products');\n }\n }\n const apiKey = generateApiKey();\n const timestamp = Date.now();\n const userName = extractNameFromEntityRef(spec.requestedBy.userId);\n const secretName = `${userName}-${spec.apiName}-${timestamp}`\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-');\n\n const secret = {\n apiVersion: 'v1',\n kind: 'Secret',\n metadata: {\n name: secretName,\n namespace: spec.apiNamespace,\n labels: {\n app: spec.apiName,\n },\n annotations: {\n 'secret.kuadrant.io/plan-id': spec.planTier,\n 'secret.kuadrant.io/user-id': spec.requestedBy.userId,\n },\n },\n stringData: {\n api_key: apiKey,\n },\n type: 'Opaque',\n };\n\n await k8sClient.createSecret(spec.apiNamespace, secret);\n\n // try to get plan limits from apiproduct or planpolicy\n let planLimits: any = null;\n try {\n const products = await k8sClient.listCustomResources('devportal.kuadrant.io', 'v1alpha1', 'apiproducts');\n const product = (products.items || []).find((p: any) =>\n p.metadata.name.includes(spec.apiName) || p.spec?.displayName?.toLowerCase().includes(spec.apiName.toLowerCase())\n );\n if (product) {\n const plan = product.spec?.plans?.find((p: any) => p.tier === spec.planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n }\n } catch (e) {\n console.warn('could not fetch apiproduct for plan limits:', e);\n }\n\n if (!planLimits) {\n try {\n const policy = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'planpolicies',\n `${spec.apiName}-plan`,\n );\n const plan = policy.spec?.plans?.find((p: any) => p.tier === spec.planTier);\n if (plan) {\n planLimits = plan.limits;\n }\n } catch (e) {\n console.warn('could not fetch planpolicy for plan limits:', e);\n }\n }\n\n // fetch httproute to get hostname\n let apiHostname = `${spec.apiName}.apps.example.com`;\n try {\n const httproute = await k8sClient.getCustomResource(\n 'gateway.networking.k8s.io',\n 'v1',\n spec.apiNamespace,\n 'httproutes',\n spec.apiName,\n );\n if (httproute.spec?.hostnames && httproute.spec.hostnames.length > 0) {\n apiHostname = httproute.spec.hostnames[0];\n }\n } catch (error) {\n console.warn('could not fetch httproute for hostname, using default:', error);\n }\n\n const status = {\n phase: 'Approved',\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n reason: comment || 'approved',\n apiKey,\n apiHostname,\n apiBasePath: '/api/v1',\n apiDescription: `${spec.apiName} api`,\n planLimits,\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n reqRef.namespace,\n 'apikeys',\n reqRef.name,\n status,\n );\n\n results.push({ namespace: reqRef.namespace, name: reqRef.name, success: true, secretName });\n } catch (error) {\n console.error(`error approving request ${reqRef.namespace}/${reqRef.name}:`, error);\n results.push({\n namespace: reqRef.namespace,\n name: reqRef.name,\n success: false,\n error: error instanceof Error ? error.message : 'unknown error'\n });\n }\n }\n\n res.json({ results });\n } catch (error) {\n console.error('error in bulk approve:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to bulk approve api key requests' });\n }\n }\n });\n\n router.post('/requests/bulk-reject', async (req, res) => {\n const parsed = bulkApproveSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError(parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n\n const decision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials },\n );\n\n if (decision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n const { requests, comment } = parsed.data;\n const reviewedBy = userEntityRef;\n const results = [];\n\n for (const reqRef of requests) {\n try {\n // fetch request to get apiproduct info\n const request = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n reqRef.namespace,\n 'apikeys',\n reqRef.name,\n );\n\n const spec = request.spec as any;\n\n // verify user owns/admins the apiproduct this request is for\n const apiProduct = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n spec.apiNamespace,\n 'apiproducts',\n spec.apiName,\n );\n\n const owner = apiProduct.metadata?.annotations?.['backstage.io/owner'];\n // owner is already in entity ref format\n\n // try update all permission first (admin)\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateAllPermission }],\n { credentials },\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // fallback to update own permission\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiProductUpdateOwnPermission }],\n { credentials },\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership of the apiproduct\n if (owner !== userEntityRef) {\n throw new NotAllowedError('you can only reject requests for your own api products');\n }\n }\n\n const status = {\n phase: 'Rejected',\n reviewedBy,\n reviewedAt: new Date().toISOString(),\n reason: comment || 'rejected',\n };\n\n await k8sClient.patchCustomResourceStatus(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n reqRef.namespace,\n 'apikeys',\n reqRef.name,\n status,\n );\n\n results.push({ namespace: reqRef.namespace, name: reqRef.name, success: true });\n } catch (error) {\n console.error(`error rejecting request ${reqRef.namespace}/${reqRef.name}:`, error);\n results.push({\n namespace: reqRef.namespace,\n name: reqRef.name,\n success: false,\n error: error instanceof Error ? error.message : 'unknown error'\n });\n }\n }\n\n res.json({ results });\n } catch (error) {\n console.error('error in bulk reject:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to bulk reject api key requests' });\n }\n }\n });\n\n router.delete('/requests/:namespace/:name', async (req, res) => {\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const { namespace, name } = req.params;\n\n // get request to verify ownership\n const request = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n name,\n );\n\n const requestUserId = request.spec?.requestedBy?.userId;\n\n // check if user can delete all requests or just their own\n const deleteAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestDeleteAllPermission }],\n { credentials }\n );\n\n const canDeleteAll = deleteAllDecision[0].result === AuthorizeResult.ALLOW;\n\n if (!canDeleteAll) {\n // check if user can delete their own requests\n const deleteOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestDeleteOwnPermission }],\n { credentials }\n );\n\n if (deleteOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership\n if (requestUserId !== userEntityRef) {\n throw new NotAllowedError('you can only delete your own api key requests');\n }\n }\n\n // if request is approved, find and delete associated secret\n if (request.status?.phase === 'Approved') {\n try {\n const apiNamespace = request.spec?.apiNamespace;\n const apiName = request.spec?.apiName;\n const planTier = request.spec?.planTier;\n\n // list secrets in the api namespace and find the one with matching annotations\n const secrets = await k8sClient.listSecrets(apiNamespace);\n const matchingSecret = secrets.items?.find((s: any) => {\n const annotations = s.metadata?.annotations || {};\n return (\n annotations['secret.kuadrant.io/user-id'] === requestUserId &&\n annotations['secret.kuadrant.io/plan-id'] === planTier &&\n s.metadata?.labels?.app === apiName\n );\n });\n\n if (matchingSecret) {\n await k8sClient.deleteSecret(apiNamespace, matchingSecret.metadata.name);\n }\n } catch (error) {\n console.warn('failed to delete associated secret:', error);\n // continue with request deletion even if secret deletion fails\n }\n }\n\n await k8sClient.deleteCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n name,\n );\n res.status(204).send();\n } catch (error) {\n console.error('error deleting api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to delete api key request' });\n }\n }\n });\n\n router.patch('/requests/:namespace/:name', async (req, res) => {\n // whitelist allowed fields for patching\n const patchSchema = z.object({\n spec: z.object({\n useCase: z.string().optional(),\n planTier: z.string().optional(),\n }).partial(),\n });\n\n const parsed = patchSchema.safeParse(req.body);\n if (!parsed.success) {\n throw new InputError('invalid patch: ' + parsed.error.toString());\n }\n\n try {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);\n const { namespace, name } = req.params;\n\n // get existing request to check ownership and status\n const existing = await k8sClient.getCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n name,\n );\n\n const requestUserId = existing.spec?.requestedBy?.userId;\n const currentPhase = existing.status?.phase || 'Pending';\n\n // only pending requests can be edited\n if (currentPhase !== 'Pending') {\n throw new NotAllowedError('only pending requests can be edited');\n }\n\n // check if user can update all requests or just their own\n const updateAllDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateAllPermission }],\n { credentials }\n );\n\n if (updateAllDecision[0].result !== AuthorizeResult.ALLOW) {\n // check if user can update their own requests\n const updateOwnDecision = await permissions.authorize(\n [{ permission: kuadrantApiKeyRequestUpdateOwnPermission }],\n { credentials }\n );\n\n if (updateOwnDecision[0].result !== AuthorizeResult.ALLOW) {\n throw new NotAllowedError('unauthorised');\n }\n\n // verify ownership\n if (requestUserId !== userEntityRef) {\n throw new NotAllowedError('you can only update your own api key requests');\n }\n }\n\n // apply validated patch\n const updated = await k8sClient.patchCustomResource(\n 'devportal.kuadrant.io',\n 'v1alpha1',\n namespace,\n 'apikeys',\n name,\n parsed.data,\n );\n\n res.json(updated);\n } catch (error) {\n console.error('error updating api key request:', error);\n if (error instanceof NotAllowedError) {\n res.status(403).json({ error: error.message });\n } else if (error instanceof InputError) {\n res.status(400).json({ error: error.message });\n } else {\n res.status(500).json({ error: 'failed to update api key request' });\n }\n }\n });\n\n // expose permissions for backstage permission framework\n router.use(createPermissionIntegrationRouter({\n permissions: kuadrantPermissions,\n }));\n\n return router;\n}\n"],"names":["randomBytes","NotAllowedError","permissions","Router","cors","express","k8sClient","KuadrantK8sClient","kuadrantApiProductListPermission","AuthorizeResult","kuadrantApiProductReadAllPermission","kuadrantApiProductReadOwnPermission","kuadrantApiProductCreatePermission","InputError","getAPIProductEntityProvider","kuadrantApiProductDeleteAllPermission","kuadrantApiProductDeleteOwnPermission","req","z","kuadrantApiProductUpdateAllPermission","kuadrantApiProductUpdateOwnPermission","kuadrantPlanPolicyListPermission","kuadrantPlanPolicyReadPermission","kuadrantApiKeyRequestCreatePermission","userName","kuadrantApiKeyRequestReadAllPermission","kuadrantApiKeyRequestReadOwnPermission","kuadrantApiKeyRequestUpdateAllPermission","kuadrantApiKeyRequestUpdateOwnPermission","kuadrantApiKeyRequestDeleteAllPermission","kuadrantApiKeyRequestDeleteOwnPermission","createPermissionIntegrationRouter","kuadrantPermissions"],"mappings":"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"}
|