screwdriver-api 8.0.80 → 8.0.81

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screwdriver-api",
3
- "version": "8.0.80",
3
+ "version": "8.0.81",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,12 +1,11 @@
1
1
  'use strict';
2
2
 
3
- const boom = require('@hapi/boom');
4
3
  const schema = require('screwdriver-data-schema');
5
4
  const joi = require('joi');
6
5
  const idSchema = schema.models.pipeline.base.extract('id');
7
6
  const scmContextSchema = schema.models.pipeline.base.extract('scmContext');
8
7
  const usernameSchema = schema.models.user.base.extract('username');
9
- const { updatePipelineAdmins } = require('./helper/updateAdmins');
8
+ const { batchUpdatePipelineAdmins } = require('./helper/updateAdmins');
10
9
 
11
10
  module.exports = () => ({
12
11
  method: 'PUT',
@@ -17,35 +16,16 @@ module.exports = () => ({
17
16
  tags: ['api', 'pipelines'],
18
17
  auth: {
19
18
  strategies: ['token'],
20
- scope: ['user', '!guest']
19
+ scope: ['user', '!guest', 'admin']
21
20
  },
22
21
  handler: async (request, h) => {
23
- const { scmContext, username, scmUserId } = request.auth.credentials;
22
+ const { scmContext, username, scope } = request.auth.credentials;
24
23
  const { payload } = request;
24
+ const { userFactory } = request.server.app;
25
+ const isSDAdmin = scope.includes('admin');
26
+ const user = await userFactory.get({ username, scmContext });
25
27
 
26
- const { bannerFactory } = request.server.app;
27
-
28
- // Check token permissions
29
- // Only SD cluster admins can update the admins
30
- const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext });
31
-
32
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
33
- username,
34
- scmDisplayName,
35
- scmUserId
36
- );
37
-
38
- if (!adminDetails.isAdmin) {
39
- throw boom.forbidden(
40
- `User ${username} does not have Screwdriver administrative privileges to update the admins for pipelines`
41
- );
42
- }
43
-
44
- await Promise.all(
45
- payload.map(e => {
46
- return updatePipelineAdmins(e, request.server);
47
- })
48
- );
28
+ await batchUpdatePipelineAdmins(payload, user, isSDAdmin, request.server);
49
29
 
50
30
  return h.response().code(204);
51
31
  },
@@ -5,62 +5,120 @@ const logger = require('screwdriver-logger');
5
5
 
6
6
  /**
7
7
  * @typedef {import('screwdriver-models/lib/pipeline')} Pipeline
8
+ * @typedef {import('screwdriver-models/lib/user')} User
8
9
  */
9
10
 
10
11
  /**
11
- * Adds the users as admins for the specified pipeline
12
+ * /**
13
+ * * Adds users as admins for the specified pipelines.
12
14
  *
13
- * @method updateBuildAndTriggerDownstreamJobs
14
- * @param {Object} config
15
- * @param {Number} config.id Pipeline id
16
- * @param {Array} [config.usernames] List of usernames to be added as admins to the pipeline
17
- * @param {String} config.scmContext SCM Context the users are associated with
18
- * @param {Object} server
19
- * @returns {Promise<Pipeline>} Updated pipeline
15
+ * @method batchUpdatePipelineAdmins
16
+ * @param {Object[]} pipelineConfigs - List of pipeline configurations
17
+ * @param {number} pipelineConfigs[].id - Pipeline ID.
18
+ * @param {string[]} [pipelineConfigs[].usernames] - Usernames to be added as admins for the pipeline.
19
+ * @param {string} pipelineConfigs[].scmContext - SCM context associated with the users.
20
+ * @param {User} user - User performing the update.
21
+ * @param {boolean} isSDAdmin - Whether the user is a Screwdriver admin.
22
+ * @param {Object} server - Hapi server instance.
23
+ * @returns {Promise<Pipeline[]>} Resolves with the updated pipelines.
20
24
  */
21
- async function updatePipelineAdmins(config, server) {
25
+ async function batchUpdatePipelineAdmins(pipelineConfigs, user, isSDAdmin, server) {
22
26
  const { pipelineFactory, userFactory } = server.app;
23
- const { id, scmContext, usernames } = config;
24
27
 
25
- const pipeline = await pipelineFactory.get({ id });
26
-
27
- // check if pipeline exists
28
- if (!pipeline) {
29
- throw boom.notFound(`Pipeline ${id} does not exist`);
30
- }
31
- if (pipeline.state === 'DELETING') {
32
- throw boom.conflict('This pipeline is being deleted.');
33
- }
34
-
35
- const users = await userFactory.list({
28
+ const pipelines = await pipelineFactory.list({
36
29
  params: {
37
- username: usernames,
38
- scmContext
30
+ id: pipelineConfigs.map(pc => pc.id)
39
31
  }
40
32
  });
41
33
 
42
- const adminUsernamesForUpdate = [];
43
- const newAdmins = new Set(pipeline.adminUserIds);
34
+ const pipelineIdToPipelineMap = pipelines.reduce((map, obj) => {
35
+ map[obj.id] = obj;
44
36
 
45
- users.forEach(user => {
46
- newAdmins.add(user.id);
47
- adminUsernamesForUpdate.push(user.username);
48
- });
37
+ return map;
38
+ }, {});
39
+
40
+ return Promise.all(
41
+ pipelineConfigs.map(async pc => {
42
+ const { id, scmContext, usernames } = pc;
43
+ const pipeline = pipelineIdToPipelineMap[id];
44
+
45
+ // check if pipeline exists
46
+ if (!pipeline) {
47
+ throw boom.notFound(`Pipeline ${id} does not exist`);
48
+ }
49
+
50
+ if (!isSDAdmin) {
51
+ await user
52
+ .getPermissions(pipeline.scmUri)
53
+ // check if user has admin access
54
+ .then(permissions => {
55
+ if (!permissions.admin) {
56
+ throw boom.forbidden(
57
+ `User ${user.username} does not have admin permission for the pipeline (id=${pipeline.id}) repo and is not allowed to update admins`
58
+ );
59
+ }
60
+ });
61
+ }
62
+
63
+ // check if pipeline is being deleted
64
+ if (pipeline.state === 'DELETING') {
65
+ throw boom.conflict(`Skipped updating admins for pipeline (id=${pipeline.id}) as it is being deleted.`);
66
+ }
67
+
68
+ const users = await userFactory.list({
69
+ params: {
70
+ username: usernames,
71
+ scmContext
72
+ }
73
+ });
49
74
 
50
- pipeline.adminUserIds = Array.from(newAdmins);
75
+ const adminUsernamesForUpdate = [];
76
+ const newAdmins = new Set(pipeline.adminUserIds);
51
77
 
52
- try {
53
- const updatedPipeline = await pipeline.update();
78
+ users.forEach(u => {
79
+ newAdmins.add(u.id);
80
+ adminUsernamesForUpdate.push(u.username);
81
+ });
54
82
 
55
- logger.info(`Updated admins ${adminUsernamesForUpdate} for pipeline(id=${id})`);
83
+ pipeline.adminUserIds = Array.from(newAdmins);
56
84
 
57
- return updatedPipeline;
58
- } catch (err) {
59
- logger.error(`Failed to update admins ${adminUsernamesForUpdate} for pipeline(id=${id}): ${err.message}`);
60
- throw boom.internal(`Failed to update admins for pipeline ${id}`);
61
- }
85
+ try {
86
+ const updatedPipeline = await pipeline.update();
87
+
88
+ logger.info(`Updated admins ${adminUsernamesForUpdate} for pipeline(id=${id})`);
89
+
90
+ return updatedPipeline;
91
+ } catch (err) {
92
+ logger.error(
93
+ `Failed to update admins ${adminUsernamesForUpdate} for pipeline(id=${id}): ${err.message}`
94
+ );
95
+ throw boom.internal(`Failed to update admins for pipeline ${id}`);
96
+ }
97
+ })
98
+ );
99
+ }
100
+
101
+ /**
102
+ * /**
103
+ * * Adds users as admins for the specified pipelines.
104
+ *
105
+ * @method updatePipelineAdmins
106
+ * @param {Object} config - Pipeline configuration
107
+ * @param {number} config.id - Pipeline ID.
108
+ * @param {string[]} [config.usernames] - Usernames to be added as admins for the pipeline.
109
+ * @param {string} config.scmContext - SCM context associated with the users.
110
+ * @param {User} user - User performing the update.
111
+ * @param {boolean} isSDAdmin - Whether the user is a Screwdriver admin.
112
+ * @param {Object} server - Hapi server instance.
113
+ * @returns {Promise<Pipeline>} Resolves with the updated pipeline.
114
+ */
115
+ async function updatePipelineAdmins(config, user, isSDAdmin, server) {
116
+ return batchUpdatePipelineAdmins([config], user, isSDAdmin, server).then(updatePipelines => {
117
+ return updatePipelines[0];
118
+ });
62
119
  }
63
120
 
64
121
  module.exports = {
122
+ batchUpdatePipelineAdmins,
65
123
  updatePipelineAdmins
66
124
  };
@@ -15,12 +15,11 @@ module.exports = () => ({
15
15
  tags: ['api', 'pipelines'],
16
16
  auth: {
17
17
  strategies: ['token'],
18
- scope: ['user', '!guest', 'pipeline']
18
+ scope: ['user', '!guest', 'admin']
19
19
  },
20
20
  handler: async (request, h) => {
21
21
  const { id } = request.params;
22
- const { scmContext, username, scmUserId, scope } = request.auth.credentials;
23
- const isPipeline = scope.includes('pipeline');
22
+ const { scmContext, username, scope } = request.auth.credentials;
24
23
 
25
24
  const { usernames } = request.payload;
26
25
  const payloadScmContext = request.payload.scmContext;
@@ -31,31 +30,11 @@ module.exports = () => ({
31
30
  throw boom.badRequest(`Payload must contain scmContext`);
32
31
  }
33
32
 
34
- const { bannerFactory } = request.server.app;
33
+ const { userFactory } = request.server.app;
35
34
 
36
- // Check token permissions
37
- if (isPipeline) {
38
- if (username !== id) {
39
- throw boom.forbidden(
40
- `User ${username} is not authorized to update admins for the pipeline (id=${id})`
41
- );
42
- }
43
- } else {
44
- // Only SD cluster admins can update the admins
45
- const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext });
35
+ const isSDAdmin = scope.includes('admin');
46
36
 
47
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
48
- username,
49
- scmDisplayName,
50
- scmUserId
51
- );
52
-
53
- if (!adminDetails.isAdmin) {
54
- throw boom.forbidden(
55
- `User ${username} does not have Screwdriver administrative privileges to update the admins for the pipeline (id=${id})`
56
- );
57
- }
58
- }
37
+ const user = await userFactory.get({ username, scmContext });
59
38
 
60
39
  const updatedPipeline = await updatePipelineAdmins(
61
40
  {
@@ -63,6 +42,8 @@ module.exports = () => ({
63
42
  scmContext: payloadScmContext,
64
43
  usernames
65
44
  },
45
+ user,
46
+ isSDAdmin,
66
47
  request.server
67
48
  );
68
49