screwdriver-api 4.1.192 → 4.1.196

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": "4.1.192",
3
+ "version": "4.1.196",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -5,6 +5,7 @@ const schema = require('screwdriver-data-schema');
5
5
  const urlLib = require('url');
6
6
  const { formatCheckoutUrl, sanitizeRootDir } = require('./helper');
7
7
  const { getUserPermissions } = require('../helper');
8
+ const ANNOTATION_USE_DEPLOY_KEY = 'screwdriver.cd/useDeployKey';
8
9
 
9
10
  module.exports = () => ({
10
11
  method: 'POST',
@@ -89,7 +90,10 @@ module.exports = () => ({
89
90
 
90
91
  await defaultCollection.update();
91
92
  }
92
- if (autoKeysGeneration) {
93
+ // check if pipeline has deploy key annotation then create secrets
94
+ const deployKeyAnnotation = pipeline.annotations && pipeline.annotations[ANNOTATION_USE_DEPLOY_KEY]
95
+
96
+ if (autoKeysGeneration || deployKeyAnnotation) {
93
97
  const privateDeployKey = await pipelineFactory.scm.addDeployKey({
94
98
  scmContext,
95
99
  checkoutUrl,
@@ -6,6 +6,7 @@ const schema = require('screwdriver-data-schema');
6
6
  const idSchema = schema.models.pipeline.base.extract('id');
7
7
  const { formatCheckoutUrl, sanitizeRootDir } = require('./helper');
8
8
  const { getUserPermissions } = require('../helper');
9
+ const ANNOTATION_USE_DEPLOY_KEY = 'screwdriver.cd/useDeployKey';
9
10
 
10
11
  /**
11
12
  * Get user permissions on old pipeline
@@ -45,10 +46,11 @@ module.exports = () => ({
45
46
  handler: async (request, h) => {
46
47
  const { checkoutUrl, rootDir, settings } = request.payload;
47
48
  const { id } = request.params;
48
- const { pipelineFactory, userFactory } = request.server.app;
49
+ const { pipelineFactory, userFactory, secretFactory } = request.server.app;
49
50
  const { scmContext, username } = request.auth.credentials;
50
51
  const scmContexts = pipelineFactory.scm.getScmContexts();
51
52
  const { isValidToken } = request.server.plugins.pipelines;
53
+ const deployKeySecret = 'SD_SCM_DEPLOY_KEY';
52
54
 
53
55
  if (!isValidToken(id, request.auth.credentials)) {
54
56
  return boom.unauthorized('Token does not have permission to this pipeline');
@@ -83,12 +85,15 @@ module.exports = () => ({
83
85
  throw boom.forbidden(`User ${user.getFullDisplayName()} does not have admin permission for this repo`);
84
86
  }
85
87
 
88
+ let token;
89
+ let formattedCheckoutUrl;
90
+
86
91
  if (checkoutUrl || rootDir) {
87
- const formattedCheckoutUrl = formatCheckoutUrl(request.payload.checkoutUrl);
92
+ formattedCheckoutUrl = formatCheckoutUrl(request.payload.checkoutUrl);
88
93
  const sanitizedRootDir = sanitizeRootDir(request.payload.rootDir);
89
94
 
90
95
  // get the user token
91
- const token = await user.unsealToken();
96
+ token = await user.unsealToken();
92
97
  // get the scm URI
93
98
  const scmUri = await pipelineFactory.scm.parseUrl({
94
99
  scmContext,
@@ -136,6 +141,32 @@ module.exports = () => ({
136
141
  // update pipeline
137
142
  const updatedPipeline = await oldPipeline.update();
138
143
 
144
+ // check if pipeline has deploy key annotation then create secrets
145
+ const deployKeyAnnotation = oldPipeline.annotations && oldPipeline.annotations[ANNOTATION_USE_DEPLOY_KEY]
146
+
147
+ if (deployKeyAnnotation) {
148
+ const deploySecret = await secretFactory.get({
149
+ pipelineId: oldPipeline.id,
150
+ name: deployKeySecret,
151
+ })
152
+
153
+ if (!deploySecret) {
154
+ const privateDeployKey = await pipelineFactory.scm.addDeployKey({
155
+ scmContext: oldPipeline.scmContext,
156
+ checkoutUrl: formattedCheckoutUrl,
157
+ token
158
+ });
159
+ const privateDeployKeyB64 = Buffer.from(privateDeployKey).toString('base64');
160
+
161
+ await secretFactory.create({
162
+ pipelineId: oldPipeline.id,
163
+ name: deployKeySecret,
164
+ value: privateDeployKeyB64,
165
+ allowInPR: true
166
+ });
167
+ }
168
+ }
169
+
139
170
  await updatedPipeline.addWebhooks(`${request.server.info.uri}/v4/webhooks`);
140
171
 
141
172
  const result = await updatedPipeline.sync();
@@ -347,6 +347,47 @@ async function triggeredPipelines(
347
347
  return currentRepoPipelines.concat(pipelinesWithSubscribedRepos);
348
348
  }
349
349
 
350
+ /**
351
+ * Start Events
352
+ * @async startEvents
353
+ * @param {Array} eventConfigs Array of event config objects
354
+ * @param {Object} eventFactory Factory to create events
355
+ * @return {Promise<Array>} Array of created events
356
+ */
357
+ async function startEvents(eventConfigs, eventFactory) {
358
+ const events = [];
359
+ let errorCount = 0;
360
+ let eventsCount = 0;
361
+
362
+ const results = await Promise.allSettled(
363
+ eventConfigs.map(eventConfig => {
364
+ if (eventConfig && eventConfig.configPipelineSha) {
365
+ eventsCount += 1;
366
+
367
+ return eventFactory.create(eventConfig);
368
+ }
369
+
370
+ return Promise.resolve(null);
371
+ })
372
+ );
373
+
374
+ results.forEach((result, i) => {
375
+ if (result.status === 'fulfilled') {
376
+ if (result.value) events.push(result.value);
377
+ } else {
378
+ errorCount += 1;
379
+ logger.error(`pipeline:${eventConfigs[i].pipelineId} error in starting event`, result.value);
380
+ }
381
+ });
382
+
383
+ if (errorCount && errorCount === eventsCount) {
384
+ // preserve current behavior of returning 500 on error
385
+ throw new Error('Failed to start any events');
386
+ }
387
+
388
+ return events;
389
+ }
390
+
350
391
  /**
351
392
  * Create events for each pipeline
352
393
  * @async createPREvents
@@ -388,7 +429,6 @@ async function createPREvents(options, request) {
388
429
  const { eventFactory, pipelineFactory, userFactory } = request.server.app;
389
430
  const scmDisplayName = scm.getDisplayName({ scmContext: scmConfig.scmContext });
390
431
  const userDisplayName = `${scmDisplayName}:${username}`;
391
- const events = [];
392
432
  let { sha } = options;
393
433
 
394
434
  scmConfig.prNum = prNum;
@@ -509,13 +549,9 @@ async function createPREvents(options, request) {
509
549
  })
510
550
  );
511
551
 
512
- eventConfigs.forEach(eventConfig => {
513
- if (eventConfig && eventConfig.configPipelineSha) {
514
- events.push(eventFactory.create(eventConfig));
515
- }
516
- });
552
+ const events = await startEvents(eventConfigs, eventFactory);
517
553
 
518
- return Promise.all(events);
554
+ return events;
519
555
  }
520
556
 
521
557
  /**
@@ -851,7 +887,6 @@ async function createEvents(
851
887
  scmConfigFromHook
852
888
  ) {
853
889
  const { action, branch, sha, username, scmContext, changedFiles, type, releaseName, ref } = parsed;
854
- const events = [];
855
890
  const meta = createMeta(parsed);
856
891
 
857
892
  const pipelineTuples = await Promise.all(
@@ -991,13 +1026,9 @@ async function createEvents(
991
1026
  })
992
1027
  );
993
1028
 
994
- eventConfigs.forEach(eventConfig => {
995
- if (eventConfig && eventConfig.configPipelineSha) {
996
- events.push(eventFactory.create(eventConfig));
997
- }
998
- });
1029
+ const events = await startEvents(eventConfigs, eventFactory);
999
1030
 
1000
- return Promise.all(events);
1031
+ return events;
1001
1032
  }
1002
1033
 
1003
1034
  /**