screwdriver-api 6.0.28 → 6.0.30

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": "6.0.28",
3
+ "version": "6.0.30",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -12,7 +12,7 @@
12
12
  "profile": "node --prof ./bin/server",
13
13
  "functional": "cucumber-js --format=progress --tags '(not @ignore) and (not @beta)' --retry 2 --fail-fast --exit",
14
14
  "functional-beta": "cucumber-js --format=progress --tags '(not @ignore) and (not @prod)' --retry 2 --fail-fast --exit",
15
- "functional-dev": "cucumber-js --format=./node_modules/cucumber-pretty --tags '(not @ignore) and (not @prod)' --retry 2 --fail-fast --exit",
15
+ "functional-dev": "cucumber-js --format=progress --tags '(not @ignore) and (not @prod)' --retry 2 --fail-fast --exit",
16
16
  "create-test-user": "node -e 'require(\"./features/scripts/create-test-user.js\")()'",
17
17
  "diagrams": "find ./design/diagrams -type f -name \\*.puml -print0 | xargs -0 -n 1 -I DIAGRAM puml generate DIAGRAM -o DIAGRAM.png",
18
18
  "semantic-release": "semantic-release pre && npm publish && semantic-release post"
@@ -138,13 +138,12 @@
138
138
  }
139
139
  },
140
140
  "devDependencies": {
141
+ "@cucumber/cucumber": "^9.0.0",
141
142
  "@octokit/rest": "^19.0.5",
142
143
  "chai": "^4.3.7",
143
144
  "chai-as-promised": "^7.1.1",
144
145
  "chai-jwt": "^2.0.0",
145
146
  "coveralls": "^3.1.1",
146
- "cucumber": "^6.0.7",
147
- "cucumber-pretty": "^6.0.1",
148
147
  "eslint": "^8.28.0",
149
148
  "eslint-config-screwdriver": "^7.0.0",
150
149
  "form-data": "^4.0.0",
@@ -107,7 +107,7 @@ const authPlugin = {
107
107
  */
108
108
  server.expose('generateProfile', config => {
109
109
  const { username, scmUserId, scmContext, scope, metadata } = config;
110
- const profile = { username, scmContext, scope, ...(metadata || {}) };
110
+ const profile = { username, scmContext, scmUserId, scope, ...(metadata || {}) };
111
111
 
112
112
  if (pluginOptions.jwtEnvironment) {
113
113
  profile.environment = pluginOptions.jwtEnvironment;
@@ -190,6 +190,7 @@ const authPlugin = {
190
190
  try {
191
191
  const { tokenFactory, userFactory, pipelineFactory, collectionFactory } = request.server.app;
192
192
  const token = await tokenFactory.get({ value: tokenValue });
193
+ const { scm } = pipelineFactory;
193
194
 
194
195
  if (!token) {
195
196
  return { isValid: false, credentials: {} };
@@ -204,10 +205,28 @@ const authPlugin = {
204
205
  return { isValid: false, credentials: {} };
205
206
  }
206
207
 
208
+ let scmUser = {};
209
+
210
+ try {
211
+ scmUser = await scm.decorateAuthor({
212
+ username: user.username,
213
+ scmContext: user.scmContext,
214
+ token: await user.unsealToken()
215
+ });
216
+ } catch (err) {
217
+ request.log(
218
+ ['auth', 'error'],
219
+ `Fails to find the user "${user.username}" in ${user.scmContext}.`
220
+ );
221
+
222
+ return { isValid: false, credentials: {} };
223
+ }
224
+
207
225
  await createDefaultCollection(user, collectionFactory);
208
226
 
209
227
  profile = {
210
228
  username: user.username,
229
+ scmUserId: scmUser.id,
211
230
  scmContext: user.scmContext,
212
231
  scope: ['user']
213
232
  };
@@ -18,13 +18,16 @@ module.exports = () => ({
18
18
 
19
19
  handler: async (request, h) => {
20
20
  const { bannerFactory } = request.server.app;
21
- const { username } = request.auth.credentials;
22
- const { scmContext } = request.auth.credentials;
21
+ const { username, scmContext, scmUserId } = request.auth.credentials;
23
22
  const { scm } = bannerFactory;
24
23
  const scmDisplayName = scm.getDisplayName({ scmContext });
25
24
 
26
25
  // lookup whether user is admin
27
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName);
26
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
27
+ username,
28
+ scmDisplayName,
29
+ scmUserId
30
+ );
28
31
 
29
32
  // verify user is authorized to create banners
30
33
  // return unauthorized if not system admin
@@ -23,21 +23,20 @@ const bannerPlugin = {
23
23
  * @param {String} scmDisplayName Scm display name of the person
24
24
  * @return {Object} Details including the display name and admin status of user
25
25
  */
26
- server.expose('screwdriverAdminDetails', (username, scmDisplayName) => {
26
+ server.expose('screwdriverAdminDetails', (username, scmDisplayName, scmUserId) => {
27
27
  // construct object with defaults to store details
28
28
  const adminDetails = {
29
29
  isAdmin: false
30
30
  };
31
31
 
32
32
  if (scmDisplayName) {
33
- const adminsList = options.admins;
33
+ const userDisplayName = options.authCheckById
34
+ ? `${scmDisplayName}:${username}:${scmUserId}`
35
+ : `${scmDisplayName}:${username}`;
36
+ const admins = options.authCheckById ? options.sdAdmins : options.admins;
34
37
 
35
- // construct displayable username string
36
- adminDetails.userDisplayName = `${scmDisplayName}:${username}`;
37
-
38
- // Check system configuration for list of system admins
39
- // set admin status true if current user is identified to be a system admin
40
- if (adminsList.length > 0 && adminsList.includes(adminDetails.userDisplayName)) {
38
+ // Check admin
39
+ if (admins.length > 0 && admins.includes(userDisplayName)) {
41
40
  adminDetails.isAdmin = true;
42
41
  }
43
42
  }
@@ -20,14 +20,16 @@ module.exports = () => ({
20
20
  handler: async (request, h) => {
21
21
  const { bannerFactory } = request.server.app;
22
22
  const { id } = request.params; // id of banner to delete
23
-
24
- const { username } = request.auth.credentials;
25
- const { scmContext } = request.auth.credentials;
23
+ const { username, scmContext, scmUserId } = request.auth.credentials;
26
24
  const { scm } = bannerFactory;
27
25
  const scmDisplayName = scm.getDisplayName({ scmContext });
28
26
 
29
27
  // lookup whether user is admin
30
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName);
28
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
29
+ username,
30
+ scmDisplayName,
31
+ scmUserId
32
+ );
31
33
 
32
34
  // verify user is authorized to remove banners
33
35
  // return unauthorized if not system admin
@@ -20,13 +20,16 @@ module.exports = () => ({
20
20
  handler: async (request, h) => {
21
21
  const { bannerFactory } = request.server.app;
22
22
  const { id } = request.params; // id of banner to update
23
- const { username } = request.auth.credentials;
24
- const { scmContext } = request.auth.credentials;
23
+ const { username, scmContext, scmUserId } = request.auth.credentials;
25
24
  const { scm } = bannerFactory;
26
25
  const scmDisplayName = scm.getDisplayName({ scmContext });
27
26
 
28
27
  // lookup whether user is admin
29
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName);
28
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
29
+ username,
30
+ scmDisplayName,
31
+ scmUserId
32
+ );
30
33
 
31
34
  // verify user is authorized to update banners
32
35
  // return unauthorized if not system admin
@@ -18,7 +18,7 @@ module.exports = () => ({
18
18
 
19
19
  handler: async (request, h) => {
20
20
  const { buildClusterFactory, bannerFactory } = request.server.app;
21
- const { username, scmContext: userContext } = request.auth.credentials;
21
+ const { username, scmContext: userContext, scmUserId } = request.auth.credentials;
22
22
  const { payload } = request;
23
23
  const { managedByScrewdriver, name, scmOrganizations } = payload;
24
24
 
@@ -27,7 +27,11 @@ module.exports = () => ({
27
27
  // Check permissions
28
28
  // Must be Screwdriver admin to add Screwdriver build cluster
29
29
  const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext: payload.scmContext });
30
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName);
30
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
31
+ username,
32
+ scmDisplayName,
33
+ scmUserId
34
+ );
31
35
 
32
36
  if (!adminDetails.isAdmin) {
33
37
  return boom.forbidden(
@@ -20,7 +20,7 @@ module.exports = () => ({
20
20
  handler: async (request, h) => {
21
21
  const { buildClusterFactory, userFactory, bannerFactory } = request.server.app;
22
22
  const { name } = request.params;
23
- const { username, scmContext } = request.auth.credentials;
23
+ const { username, scmContext, scmUserId } = request.auth.credentials;
24
24
  const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext });
25
25
 
26
26
  // Fetch the buildCluster and user models
@@ -46,7 +46,8 @@ module.exports = () => ({
46
46
 
47
47
  const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
48
48
  username,
49
- scmDisplayName
49
+ scmDisplayName,
50
+ scmUserId
50
51
  );
51
52
 
52
53
  if (!adminDetails.isAdmin) {
@@ -20,7 +20,7 @@ module.exports = () => ({
20
20
  handler: async (request, h) => {
21
21
  const { buildClusterFactory, bannerFactory } = request.server.app;
22
22
  const { name } = request.params; // name of build cluster to update
23
- const { username, scmContext: userContext } = request.auth.credentials;
23
+ const { username, scmContext: userContext, scmUserId } = request.auth.credentials;
24
24
  const { payload } = request;
25
25
  const { managedByScrewdriver, scmOrganizations } = payload;
26
26
 
@@ -29,7 +29,11 @@ module.exports = () => ({
29
29
  // Check permissions
30
30
  // Must be Screwdriver admin to update Screwdriver build cluster
31
31
  const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext: userContext });
32
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName);
32
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
33
+ username,
34
+ scmDisplayName,
35
+ scmUserId
36
+ );
33
37
 
34
38
  if (!adminDetails.isAdmin) {
35
39
  return boom.forbidden(
@@ -26,11 +26,11 @@ module.exports = config => ({
26
26
  return h.response(data).code(200);
27
27
  }
28
28
  const buildId = req.params.id;
29
- const { username, scope, scmContext } = req.auth.credentials;
29
+ const { username, scope, scmContext, scmUserId } = req.auth.credentials;
30
30
  const isBuild = scope.includes('build');
31
31
  const { buildFactory } = req.server.app;
32
32
  const scmDisplayName = buildFactory.scm.getDisplayName({ scmContext })
33
- const adminDetails = req.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName);
33
+ const adminDetails = req.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName, scmUserId);
34
34
 
35
35
  if (scope.includes('user') && !adminDetails.isAdmin) {
36
36
  return boom.forbidden(`User ${adminDetails.userDisplayName} does not have Screwdriver administrative privileges.`)
@@ -93,13 +93,13 @@ async function getBuildToUpdate(id, buildFactory) {
93
93
  */
94
94
  async function validateUserPermission(build, request) {
95
95
  const { jobFactory, userFactory, bannerFactory, pipelineFactory } = request.server.app;
96
- const { username, scmContext } = request.auth.credentials;
96
+ const { username, scmContext, scmUserId } = request.auth.credentials;
97
97
 
98
98
  const { status: desiredStatus } = request.payload;
99
99
 
100
100
  const scmDisplayName = bannerFactory.scm.getDisplayName({ scmContext });
101
101
  // Check if Screwdriver admin
102
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName);
102
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName, scmUserId);
103
103
 
104
104
  // Check desired status
105
105
  if (adminDetails.isAdmin) {
@@ -22,7 +22,7 @@ module.exports = () => ({
22
22
 
23
23
  handler: async (request, h) => {
24
24
  const { eventFactory, pipelineFactory, userFactory } = request.server.app;
25
- const { username, scmContext } = request.auth.credentials;
25
+ const { username, scmContext, scmUserId } = request.auth.credentials;
26
26
  const { isValidToken } = request.server.plugins.pipelines;
27
27
  const eventId = request.params.id;
28
28
  const { updateAdmins } = request.server.plugins.events;
@@ -47,7 +47,11 @@ module.exports = () => ({
47
47
 
48
48
  // Check permissions
49
49
  const permissions = await user.getPermissions(pipeline.scmUri);
50
- const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmContext);
50
+ const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
51
+ username,
52
+ scmContext,
53
+ scmUserId
54
+ );
51
55
  const isPrOwner = hoek.reach(event, 'commit.author.username') === username;
52
56
 
53
57
  // PR author should be able to stop their own PR event
@@ -104,7 +104,7 @@ const pipelinesPlugin = {
104
104
  * @return {Object} pipeline
105
105
  */
106
106
  server.expose('canAccessPipeline', (credentials, pipelineId, permission, app) => {
107
- const { username, scmContext, scope } = credentials;
107
+ const { username, scmContext, scope, scmUserId } = credentials;
108
108
  const { userFactory, pipelineFactory } = app;
109
109
 
110
110
  return pipelineFactory.get(pipelineId).then(pipeline => {
@@ -141,7 +141,8 @@ const pipelinesPlugin = {
141
141
  const scmDisplayName = pipelineFactory.scm.getDisplayName({ scmContext });
142
142
  const adminDetails = server.plugins.banners.screwdriverAdminDetails(
143
143
  username,
144
- scmDisplayName
144
+ scmDisplayName,
145
+ scmUserId
145
146
  );
146
147
 
147
148
  if (adminDetails.isAdmin) {
@@ -81,13 +81,17 @@ module.exports = () => ({
81
81
  return Promise.all(pipelineArray)
82
82
  .then(pipelineArrays => [].concat(...pipelineArrays))
83
83
  .then(allPipelines => {
84
- const { username, scope, scmContext } = request.auth.credentials;
84
+ const { username, scope, scmContext, scmUserId } = request.auth.credentials;
85
85
  let adminDetails;
86
86
 
87
87
  if (scmContext) {
88
88
  const scmDisplayName = pipelineFactory.scm.getDisplayName({ scmContext });
89
89
 
90
- adminDetails = request.server.plugins.banners.screwdriverAdminDetails(username, scmDisplayName);
90
+ adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
91
+ username,
92
+ scmDisplayName,
93
+ scmUserId
94
+ );
91
95
  }
92
96
 
93
97
  if (scope.includes('user') && adminDetails && adminDetails.isAdmin) {
@@ -21,8 +21,7 @@ module.exports = () => ({
21
21
  handler: async (request, h) => {
22
22
  const { pipelineFactory, bannerFactory } = request.server.app;
23
23
  const { userFactory } = request.server.app;
24
- const { username } = request.auth.credentials;
25
- const { scmContext } = request.auth.credentials;
24
+ const { username, scmContext, scmUserId } = request.auth.credentials;
26
25
 
27
26
  // Fetch the pipeline and user models
28
27
  return Promise.all([pipelineFactory.get(request.params.id), userFactory.get({ username, scmContext })])
@@ -57,7 +56,8 @@ module.exports = () => ({
57
56
  // Lookup whether user is admin
58
57
  const adminDetails = request.server.plugins.banners.screwdriverAdminDetails(
59
58
  username,
60
- scmDisplayName
59
+ scmDisplayName,
60
+ scmUserId
61
61
  );
62
62
 
63
63
  // Allow cluster admins to remove pipeline