@backstage/plugin-kubernetes-backend 0.21.6 → 0.21.7-next.0
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.
- package/CHANGELOG.md +12 -0
- package/config.schema.json +4 -0
- package/dist/auth/AwsIamStrategy.cjs.js +20 -10
- package/dist/auth/AwsIamStrategy.cjs.js.map +1 -1
- package/dist/cluster-locator/index.cjs.js +30 -6
- package/dist/cluster-locator/index.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +1 -1
- package/package.json +18 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @backstage/plugin-kubernetes-backend
|
|
2
2
|
|
|
3
|
+
## 0.21.7-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 684c9b9: Fixed `AwsIamStrategy` to resolve account-specific AWS credentials when an assume role ARN is configured, enabling support for `webIdentityTokenFile` and `accountDefaults` in environments without default AWS credentials.
|
|
8
|
+
- f0834bd: Added a `kubernetes.clusterLocatorContinueOnError` configuration option. When set to `true`, a failing cluster locator no longer causes the entire cluster list request to fail — errors are logged and clusters from the remaining successful locators are still returned. The default is `false`, preserving the existing behavior.
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/backend-plugin-api@1.10.0-next.0
|
|
11
|
+
- @backstage/plugin-kubernetes-node@0.4.7-next.0
|
|
12
|
+
- @backstage/plugin-permission-node@0.11.3-next.0
|
|
13
|
+
- @backstage/plugin-catalog-node@2.2.4-next.0
|
|
14
|
+
|
|
3
15
|
## 0.21.6
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/config.schema.json
CHANGED
|
@@ -43,6 +43,10 @@
|
|
|
43
43
|
"type"
|
|
44
44
|
]
|
|
45
45
|
},
|
|
46
|
+
"clusterLocatorContinueOnError": {
|
|
47
|
+
"type": "boolean",
|
|
48
|
+
"description": "Whether to continue returning clusters from successful locators when one or more locators fail. When set to `true`, errors are logged and only the clusters from successful locators are returned. Defaults to `false`, which preserves the existing behaviour of failing the entire request when any locator errors."
|
|
49
|
+
},
|
|
46
50
|
"clusterLocatorMethods": {
|
|
47
51
|
"type": "array",
|
|
48
52
|
"items": {
|
|
@@ -27,19 +27,29 @@ class AwsIamStrategy {
|
|
|
27
27
|
}
|
|
28
28
|
async getBearerToken(clusterId, assumeRole, externalId) {
|
|
29
29
|
const region = process.env.AWS_REGION ?? defaultRegion;
|
|
30
|
-
let
|
|
30
|
+
let masterCredentials;
|
|
31
31
|
if (assumeRole) {
|
|
32
|
-
|
|
33
|
-
masterCredentials:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
params: {
|
|
38
|
-
RoleArn: assumeRole,
|
|
39
|
-
ExternalId: externalId
|
|
32
|
+
try {
|
|
33
|
+
masterCredentials = (await this.credsManager.getCredentialProvider({ arn: assumeRole })).sdkCredentialProvider;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (!(error instanceof Error) || !error.message.includes("There is no AWS integration that matches")) {
|
|
36
|
+
throw error;
|
|
40
37
|
}
|
|
41
|
-
|
|
38
|
+
masterCredentials = (await this.credsManager.getCredentialProvider()).sdkCredentialProvider;
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
masterCredentials = (await this.credsManager.getCredentialProvider()).sdkCredentialProvider;
|
|
42
42
|
}
|
|
43
|
+
const credentials = assumeRole ? credentialProviders.fromTemporaryCredentials({
|
|
44
|
+
masterCredentials,
|
|
45
|
+
clientConfig: {
|
|
46
|
+
region
|
|
47
|
+
},
|
|
48
|
+
params: {
|
|
49
|
+
RoleArn: assumeRole,
|
|
50
|
+
ExternalId: externalId
|
|
51
|
+
}
|
|
52
|
+
}) : masterCredentials;
|
|
43
53
|
const signer = new signatureV4.SignatureV4({
|
|
44
54
|
credentials,
|
|
45
55
|
region,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AwsIamStrategy.cjs.js","sources":["../../src/auth/AwsIamStrategy.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport { SignatureV4 } from '@smithy/signature-v4';\nimport { Sha256 } from '@aws-crypto/sha256-js';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport { Config } from '@backstage/config';\nimport {\n ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE,\n ANNOTATION_KUBERNETES_AWS_CLUSTER_ID,\n ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID,\n} from '@backstage/plugin-kubernetes-common';\nimport {\n AuthMetadata,\n AuthenticationStrategy,\n ClusterDetails,\n KubernetesCredential,\n} from '@backstage/plugin-kubernetes-node';\n\n/**\n *\n * @public\n */\nexport type SigningCreds = {\n accessKeyId: string | undefined;\n secretAccessKey: string | undefined;\n sessionToken: string | undefined;\n};\n\nconst defaultRegion = 'us-east-1';\n\n/**\n *\n * @public\n */\nexport class AwsIamStrategy implements AuthenticationStrategy {\n private readonly credsManager: AwsCredentialsManager;\n\n constructor(opts: { config: Config }) {\n this.credsManager = DefaultAwsCredentialsManager.fromConfig(opts.config);\n }\n\n public async getCredential(\n clusterDetails: ClusterDetails,\n ): Promise<KubernetesCredential> {\n return {\n type: 'bearer token',\n token: await this.getBearerToken(\n clusterDetails.authMetadata[ANNOTATION_KUBERNETES_AWS_CLUSTER_ID] ??\n clusterDetails.name,\n clusterDetails.authMetadata[ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE],\n clusterDetails.authMetadata[ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID],\n ),\n };\n }\n\n public validateCluster(): Error[] {\n return [];\n }\n\n private async getBearerToken(\n clusterId: string,\n assumeRole?: string,\n externalId?: string,\n ): Promise<string> {\n const region = process.env.AWS_REGION ?? defaultRegion;\n\n let
|
|
1
|
+
{"version":3,"file":"AwsIamStrategy.cjs.js","sources":["../../src/auth/AwsIamStrategy.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport { SignatureV4 } from '@smithy/signature-v4';\nimport { Sha256 } from '@aws-crypto/sha256-js';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport { Config } from '@backstage/config';\nimport {\n ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE,\n ANNOTATION_KUBERNETES_AWS_CLUSTER_ID,\n ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID,\n} from '@backstage/plugin-kubernetes-common';\nimport {\n AuthMetadata,\n AuthenticationStrategy,\n ClusterDetails,\n KubernetesCredential,\n} from '@backstage/plugin-kubernetes-node';\n\n/**\n *\n * @public\n */\nexport type SigningCreds = {\n accessKeyId: string | undefined;\n secretAccessKey: string | undefined;\n sessionToken: string | undefined;\n};\n\nconst defaultRegion = 'us-east-1';\n\n/**\n *\n * @public\n */\nexport class AwsIamStrategy implements AuthenticationStrategy {\n private readonly credsManager: AwsCredentialsManager;\n\n constructor(opts: { config: Config }) {\n this.credsManager = DefaultAwsCredentialsManager.fromConfig(opts.config);\n }\n\n public async getCredential(\n clusterDetails: ClusterDetails,\n ): Promise<KubernetesCredential> {\n return {\n type: 'bearer token',\n token: await this.getBearerToken(\n clusterDetails.authMetadata[ANNOTATION_KUBERNETES_AWS_CLUSTER_ID] ??\n clusterDetails.name,\n clusterDetails.authMetadata[ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE],\n clusterDetails.authMetadata[ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID],\n ),\n };\n }\n\n public validateCluster(): Error[] {\n return [];\n }\n\n private async getBearerToken(\n clusterId: string,\n assumeRole?: string,\n externalId?: string,\n ): Promise<string> {\n const region = process.env.AWS_REGION ?? defaultRegion;\n\n let masterCredentials;\n if (assumeRole) {\n try {\n masterCredentials = (\n await this.credsManager.getCredentialProvider({ arn: assumeRole })\n ).sdkCredentialProvider;\n } catch (error) {\n if (\n !(error instanceof Error) ||\n !error.message.includes('There is no AWS integration that matches')\n ) {\n throw error;\n }\n masterCredentials = (await this.credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n } else {\n masterCredentials = (await this.credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n\n const credentials = assumeRole\n ? fromTemporaryCredentials({\n masterCredentials,\n clientConfig: {\n region,\n },\n params: {\n RoleArn: assumeRole,\n ExternalId: externalId,\n },\n })\n : masterCredentials;\n\n const signer = new SignatureV4({\n credentials,\n region,\n service: 'sts',\n sha256: Sha256,\n });\n\n const request = await signer.presign(\n {\n headers: {\n host: `sts.${region}.amazonaws.com`,\n 'x-k8s-aws-id': clusterId,\n },\n hostname: `sts.${region}.amazonaws.com`,\n method: 'GET',\n path: '/',\n protocol: 'https:',\n query: {\n Action: 'GetCallerIdentity',\n Version: '2011-06-15',\n },\n },\n { expiresIn: 0 },\n );\n\n const query = Object.keys(request?.query ?? {})\n .map(\n q =>\n `${encodeURIComponent(q)}=${encodeURIComponent(\n request.query?.[q] as string,\n )}`,\n )\n .join('&');\n\n const url = `https://${request.hostname}${request.path}?${query}`;\n\n return `k8s-aws-v1.${Buffer.from(url).toString('base64url')}`;\n }\n\n public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata {\n return {};\n }\n}\n"],"names":["DefaultAwsCredentialsManager","ANNOTATION_KUBERNETES_AWS_CLUSTER_ID","ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE","ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID","fromTemporaryCredentials","SignatureV4","Sha256"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
3
4
|
var ConfigClusterLocator = require('./ConfigClusterLocator.cjs.js');
|
|
4
5
|
var GkeClusterLocator = require('./GkeClusterLocator.cjs.js');
|
|
5
6
|
var CatalogClusterLocator = require('./CatalogClusterLocator.cjs.js');
|
|
@@ -8,18 +9,36 @@ var LocalKubectlProxyLocator = require('./LocalKubectlProxyLocator.cjs.js');
|
|
|
8
9
|
class CombinedClustersSupplier {
|
|
9
10
|
clusterSuppliers;
|
|
10
11
|
logger;
|
|
11
|
-
|
|
12
|
+
continueOnError;
|
|
13
|
+
constructor(clusterSuppliers, logger, continueOnError = false) {
|
|
12
14
|
this.clusterSuppliers = clusterSuppliers;
|
|
13
15
|
this.logger = logger;
|
|
16
|
+
this.continueOnError = continueOnError;
|
|
14
17
|
}
|
|
15
18
|
async getClusters(options) {
|
|
16
|
-
const clusters = await Promise.all(
|
|
19
|
+
const clusters = this.continueOnError ? await this.getClustersSettled(options) : await Promise.all(
|
|
17
20
|
this.clusterSuppliers.map((supplier) => supplier.getClusters(options))
|
|
18
|
-
).then((res) =>
|
|
19
|
-
return res.flat();
|
|
20
|
-
});
|
|
21
|
+
).then((res) => res.flat());
|
|
21
22
|
return this.warnDuplicates(clusters);
|
|
22
23
|
}
|
|
24
|
+
async getClustersSettled(options) {
|
|
25
|
+
const results = await Promise.allSettled(
|
|
26
|
+
this.clusterSuppliers.map((supplier) => supplier.getClusters(options))
|
|
27
|
+
);
|
|
28
|
+
const clusters = [];
|
|
29
|
+
for (let i = 0; i < results.length; i++) {
|
|
30
|
+
const result = results[i];
|
|
31
|
+
if (result.status === "fulfilled") {
|
|
32
|
+
clusters.push(...result.value);
|
|
33
|
+
} else {
|
|
34
|
+
this.logger.error(
|
|
35
|
+
`Failed to retrieve clusters from cluster locator method #${i + 1}`,
|
|
36
|
+
errors.toError(result.reason)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return clusters;
|
|
41
|
+
}
|
|
23
42
|
warnDuplicates(clusters) {
|
|
24
43
|
const clusterNames = /* @__PURE__ */ new Set();
|
|
25
44
|
const duplicatedNames = /* @__PURE__ */ new Set();
|
|
@@ -61,7 +80,12 @@ const getCombinedClusterSupplier = (rootConfig, catalogService, authStrategy, lo
|
|
|
61
80
|
);
|
|
62
81
|
}
|
|
63
82
|
});
|
|
64
|
-
|
|
83
|
+
const continueOnError = rootConfig.getOptionalBoolean("kubernetes.clusterLocatorContinueOnError") ?? false;
|
|
84
|
+
return new CombinedClustersSupplier(
|
|
85
|
+
clusterSuppliers,
|
|
86
|
+
logger,
|
|
87
|
+
continueOnError
|
|
88
|
+
);
|
|
65
89
|
};
|
|
66
90
|
|
|
67
91
|
exports.getCombinedClusterSupplier = getCombinedClusterSupplier;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../../src/cluster-locator/index.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { Duration } from 'luxon';\nimport { ConfigClusterLocator } from './ConfigClusterLocator';\nimport { GkeClusterLocator } from './GkeClusterLocator';\nimport { CatalogClusterLocator } from './CatalogClusterLocator';\nimport { LocalKubectlProxyClusterLocator } from './LocalKubectlProxyLocator';\nimport {\n AuthService,\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport {\n AuthenticationStrategy,\n ClusterDetails,\n KubernetesClustersSupplier,\n} from '@backstage/plugin-kubernetes-node';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\n\nclass CombinedClustersSupplier implements KubernetesClustersSupplier {\n readonly clusterSuppliers: KubernetesClustersSupplier[];\n readonly logger: LoggerService;\n\n constructor(\n clusterSuppliers: KubernetesClustersSupplier[],\n logger: LoggerService,\n ) {\n this.clusterSuppliers = clusterSuppliers;\n this.logger = logger;\n }\n\n async getClusters(options: {\n credentials: BackstageCredentials;\n }): Promise<ClusterDetails[]> {\n const clusters = await Promise.all(\n
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../src/cluster-locator/index.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { toError } from '@backstage/errors';\nimport { Duration } from 'luxon';\nimport { ConfigClusterLocator } from './ConfigClusterLocator';\nimport { GkeClusterLocator } from './GkeClusterLocator';\nimport { CatalogClusterLocator } from './CatalogClusterLocator';\nimport { LocalKubectlProxyClusterLocator } from './LocalKubectlProxyLocator';\nimport {\n AuthService,\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport {\n AuthenticationStrategy,\n ClusterDetails,\n KubernetesClustersSupplier,\n} from '@backstage/plugin-kubernetes-node';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\n\nclass CombinedClustersSupplier implements KubernetesClustersSupplier {\n readonly clusterSuppliers: KubernetesClustersSupplier[];\n readonly logger: LoggerService;\n readonly continueOnError: boolean;\n\n constructor(\n clusterSuppliers: KubernetesClustersSupplier[],\n logger: LoggerService,\n continueOnError: boolean = false,\n ) {\n this.clusterSuppliers = clusterSuppliers;\n this.logger = logger;\n this.continueOnError = continueOnError;\n }\n\n async getClusters(options: {\n credentials: BackstageCredentials;\n }): Promise<ClusterDetails[]> {\n const clusters = this.continueOnError\n ? await this.getClustersSettled(options)\n : await Promise.all(\n this.clusterSuppliers.map(supplier => supplier.getClusters(options)),\n ).then(res => res.flat());\n return this.warnDuplicates(clusters);\n }\n\n private async getClustersSettled(options: {\n credentials: BackstageCredentials;\n }): Promise<ClusterDetails[]> {\n const results = await Promise.allSettled(\n this.clusterSuppliers.map(supplier => supplier.getClusters(options)),\n );\n const clusters: ClusterDetails[] = [];\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n if (result.status === 'fulfilled') {\n clusters.push(...result.value);\n } else {\n this.logger.error(\n `Failed to retrieve clusters from cluster locator method #${i + 1}`,\n toError(result.reason),\n );\n }\n }\n return clusters;\n }\n\n private warnDuplicates(clusters: ClusterDetails[]): ClusterDetails[] {\n const clusterNames = new Set<string>();\n const duplicatedNames = new Set<string>();\n for (const clusterName of clusters.map(c => c.name)) {\n if (clusterNames.has(clusterName)) {\n duplicatedNames.add(clusterName);\n } else {\n clusterNames.add(clusterName);\n }\n }\n for (const clusterName of duplicatedNames) {\n this.logger.warn(`Duplicate cluster name '${clusterName}'`);\n }\n return clusters;\n }\n}\n\nexport const getCombinedClusterSupplier = (\n rootConfig: Config,\n catalogService: CatalogService,\n authStrategy: AuthenticationStrategy,\n logger: LoggerService,\n refreshInterval: Duration | undefined = undefined,\n auth: AuthService,\n): KubernetesClustersSupplier => {\n const clusterSuppliers = rootConfig\n .getConfigArray('kubernetes.clusterLocatorMethods')\n .map(clusterLocatorMethod => {\n const type = clusterLocatorMethod.getString('type');\n switch (type) {\n case 'catalog':\n return CatalogClusterLocator.fromConfig(catalogService, auth);\n case 'localKubectlProxy':\n return new LocalKubectlProxyClusterLocator();\n case 'config':\n return ConfigClusterLocator.fromConfig(\n clusterLocatorMethod,\n authStrategy,\n );\n case 'gke':\n return GkeClusterLocator.fromConfig(\n clusterLocatorMethod,\n logger,\n refreshInterval,\n );\n default:\n throw new Error(\n `Unsupported kubernetes.clusterLocatorMethods: \"${type}\"`,\n );\n }\n });\n\n const continueOnError =\n rootConfig.getOptionalBoolean('kubernetes.clusterLocatorContinueOnError') ??\n false;\n\n return new CombinedClustersSupplier(\n clusterSuppliers,\n logger,\n continueOnError,\n );\n};\n"],"names":["toError","CatalogClusterLocator","LocalKubectlProxyClusterLocator","ConfigClusterLocator","GkeClusterLocator"],"mappings":"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"}
|
package/dist/package.json.cjs.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-kubernetes-backend",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.7-next.0",
|
|
4
4
|
"description": "A Backstage backend plugin that integrates towards Kubernetes",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "backend-plugin",
|
|
@@ -49,18 +49,18 @@
|
|
|
49
49
|
"@aws-crypto/sha256-js": "^5.0.0",
|
|
50
50
|
"@aws-sdk/credential-providers": "^3.350.0",
|
|
51
51
|
"@azure/identity": "^4.0.0",
|
|
52
|
-
"@backstage/backend-plugin-api": "
|
|
53
|
-
"@backstage/catalog-client": "
|
|
54
|
-
"@backstage/catalog-model": "
|
|
55
|
-
"@backstage/config": "
|
|
56
|
-
"@backstage/errors": "
|
|
57
|
-
"@backstage/integration-aws-node": "
|
|
58
|
-
"@backstage/plugin-catalog-node": "
|
|
59
|
-
"@backstage/plugin-kubernetes-common": "
|
|
60
|
-
"@backstage/plugin-kubernetes-node": "
|
|
61
|
-
"@backstage/plugin-permission-common": "
|
|
62
|
-
"@backstage/plugin-permission-node": "
|
|
63
|
-
"@backstage/types": "
|
|
52
|
+
"@backstage/backend-plugin-api": "1.10.0-next.0",
|
|
53
|
+
"@backstage/catalog-client": "1.16.1",
|
|
54
|
+
"@backstage/catalog-model": "1.9.0",
|
|
55
|
+
"@backstage/config": "1.3.8",
|
|
56
|
+
"@backstage/errors": "1.3.1",
|
|
57
|
+
"@backstage/integration-aws-node": "0.2.0",
|
|
58
|
+
"@backstage/plugin-catalog-node": "2.2.4-next.0",
|
|
59
|
+
"@backstage/plugin-kubernetes-common": "0.9.12",
|
|
60
|
+
"@backstage/plugin-kubernetes-node": "0.4.7-next.0",
|
|
61
|
+
"@backstage/plugin-permission-common": "0.9.9",
|
|
62
|
+
"@backstage/plugin-permission-node": "0.11.3-next.0",
|
|
63
|
+
"@backstage/types": "1.2.2",
|
|
64
64
|
"@google-cloud/container": "^5.0.0",
|
|
65
65
|
"@jest-mock/express": "^2.0.1",
|
|
66
66
|
"@kubernetes/client-node": "1.4.0",
|
|
@@ -75,11 +75,11 @@
|
|
|
75
75
|
"node-fetch": "^2.7.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
|
-
"@backstage/backend-defaults": "
|
|
79
|
-
"@backstage/backend-test-utils": "
|
|
80
|
-
"@backstage/cli": "
|
|
81
|
-
"@backstage/plugin-permission-backend": "
|
|
82
|
-
"@backstage/plugin-permission-backend-module-allow-all-policy": "
|
|
78
|
+
"@backstage/backend-defaults": "0.17.6-next.0",
|
|
79
|
+
"@backstage/backend-test-utils": "1.11.6-next.0",
|
|
80
|
+
"@backstage/cli": "0.36.4",
|
|
81
|
+
"@backstage/plugin-permission-backend": "0.7.15-next.0",
|
|
82
|
+
"@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.22-next.0",
|
|
83
83
|
"@types/express": "^4.17.6",
|
|
84
84
|
"msw": "^1.0.0",
|
|
85
85
|
"supertest": "^7.0.0",
|