Skip to content

Commit

Permalink
feat(2437): Support read-only SCM (#191)
Browse files Browse the repository at this point in the history
  • Loading branch information
tkyi authored Jun 28, 2021
1 parent 69139cf commit 8cbd8ac
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The class has a variety of knobs to tweak when interacting with GitHub.
| config.https | Boolean | false | Is the Screwdriver API running over HTTPS |
| config.oauthClientId | String | | OAuth Client ID provided by GitHub application |
| config.oauthClientSecret | String | | OAuth Client Secret provided by GitHub application |
| config.readOnly | Object | {} | Config with readOnly info: enabled, username, accessToken, cloneType |
| config.fusebox | Object | {} | [Circuit Breaker configuration][circuitbreaker] |
| config.secret | String | | Secret to validate the signature of webhook events |
| config.privateRepo | Boolean | false | Request 'repo' scope, which allows read/write access for public & private repos
Expand Down
28 changes: 23 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ class GithubScm extends Scm {
* @param {String} [config.gheProtocol=https] If using GitHub Enterprise, the protocol to use
* @param {String} [config.username=sd-buildbot] GitHub username for checkout
* @param {String} [config.email=dev-null@screwdriver.cd] GitHub user email for checkout
* @param {Object} [options.readOnly={}] Read-only SCM instance config with: enabled, username, accessToken, cloneType
* @param {Boolean} [config.https=false] Is the Screwdriver API running over HTTPS
* @param {String} config.oauthClientId OAuth Client ID provided by GitHub application
* @param {String} config.oauthClientSecret OAuth Client Secret provided by GitHub application
Expand All @@ -139,6 +140,12 @@ class GithubScm extends Scm {
email: joi.string().optional().default('dev-null@screwdriver.cd'),
commentUserToken: joi.string().optional().description('Token for PR comments'),
autoDeployKeyGeneration: joi.boolean().optional().default(false),
readOnly: joi.object().keys({
enabled: joi.boolean().optional(),
username: joi.string().optional(),
accessToken: joi.string().optional(),
cloneType: joi.string().valid('https', 'ssh').optional().default('https')
}).optional().default({}),
https: joi.boolean().optional().default(false),
oauthClientId: joi.string().required(),
oauthClientSecret: joi.string().required(),
Expand Down Expand Up @@ -555,11 +562,22 @@ class GithubScm extends Scm {

// Export environment variables
command.push('echo Exporting environment variables');
command.push('if [ ! -z $SCM_CLONE_TYPE ] && [ $SCM_CLONE_TYPE = ssh ]; ' +
`then export SCM_URL=${sshCheckoutUrl}; ` +
'elif [ ! -z $SCM_USERNAME ] && [ ! -z $SCM_ACCESS_TOKEN ]; ' +
`then export SCM_URL=https://$SCM_USERNAME:$SCM_ACCESS_TOKEN@${checkoutUrl}; ` +
`else export SCM_URL=https://${checkoutUrl}; fi`);
// Use read-only clone type
if (hoek.reach(this.config, 'readOnly.enabled')) {
if (hoek.reach(this.config, 'readOnly.cloneType') === 'ssh') {
command.push(`export SCM_URL=${sshCheckoutUrl}`);
} else {
command.push('if [ ! -z $SCM_USERNAME ] && [ ! -z $SCM_ACCESS_TOKEN ]; ' +
`then export SCM_URL=https://$SCM_USERNAME:$SCM_ACCESS_TOKEN@${checkoutUrl}; ` +
`else export SCM_URL=https://${checkoutUrl}; fi`);
}
} else {
command.push('if [ ! -z $SCM_CLONE_TYPE ] && [ $SCM_CLONE_TYPE = ssh ]; ' +
`then export SCM_URL=${sshCheckoutUrl}; ` +
'elif [ ! -z $SCM_USERNAME ] && [ ! -z $SCM_ACCESS_TOKEN ]; ' +
`then export SCM_URL=https://$SCM_USERNAME:$SCM_ACCESS_TOKEN@${checkoutUrl}; ` +
`else export SCM_URL=https://${checkoutUrl}; fi`);
}
command.push('export GIT_URL=$SCM_URL.git');
// git 1.7.1 doesn't support --no-edit with merge, this should do same thing
command.push('export GIT_MERGE_AUTOEDIT=no');
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,22 @@
"chai": "^3.5.0",
"eslint": "^4.19.1",
"eslint-config-screwdriver": "^3.0.1",
"mocha": "^8.2.1",
"mocha": "^8.4.0",
"mocha-multi-reporters": "^1.5.1",
"mocha-sonarqube-reporter": "^1.0.2",
"nyc": "^15.0.0",
"mockery": "^2.0.0",
"nyc": "^15.0.0",
"sinon": "^7.5.0"
},
"dependencies": {
"@hapi/hoek": "^9.1.1",
"@octokit/rest": "^18.5.2",
"@hapi/hoek": "^9.2.0",
"@octokit/rest": "^18.6.2",
"@octokit/webhooks": "^7.24.3",
"circuit-fuses": "^4.0.5",
"circuit-fuses": "^4.0.6",
"joi": "^17.4.0",
"screwdriver-data-schema": "^21.3.0",
"screwdriver-logger": "^1.0.2",
"screwdriver-scm-base": "^7.1.3",
"screwdriver-scm-base": "^7.2.1",
"ssh-keygen": "^0.5.0"
},
"release": {
Expand Down
4 changes: 4 additions & 0 deletions test/data/readOnlyCommandsHttps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "sd-checkout-code",
"command": "export SD_GIT_WRAPPER=\"$(if [ `uname` = 'Darwin' ]; then echo 'eval'; else echo 'sd-step exec core/git'; fi)\" && if [ ! -z $SD_SCM_DEPLOY_KEY ]; then export SCM_CLONE_TYPE=ssh; fi && echo Exporting environment variables && if [ ! -z $SCM_USERNAME ] && [ ! -z $SCM_ACCESS_TOKEN ]; then export SCM_URL=https://$SCM_USERNAME:$SCM_ACCESS_TOKEN@github.com/screwdriver-cd/guide; else export SCM_URL=https://github.com/screwdriver-cd/guide; fi && export GIT_URL=$SCM_URL.git && export GIT_MERGE_AUTOEDIT=no && if [ ! -z $SD_SCM_DEPLOY_KEY ] && [ $SCM_CLONE_TYPE = ssh ]; then echo $SD_SCM_DEPLOY_KEY | base64 -d > /tmp/git_key && echo \"\" >> /tmp/git_key && chmod 600 /tmp/git_key && export GIT_SSH_COMMAND=\"ssh -i /tmp/git_key\" && mkdir -p ~/.ssh/ && printf \"%s\n\" \"CiAgICAgICAgSG9zdCBnaXRodWIuY29tCiAgICAgICAgICAgIFN0cmljdEhvc3RLZXlDaGVja2luZyBubwogICAgICAgIA==\" | base64 -d >> ~/.ssh/config; fi && echo Setting user name and user email && $SD_GIT_WRAPPER \"git config --global user.name sd-buildbot\" && $SD_GIT_WRAPPER \"git config --global user.email dev-null@screwdriver.cd\" && export SD_CHECKOUT_DIR_FINAL=$SD_SOURCE_DIR && if [ ! -z $SD_CHECKOUT_DIR ]; then export SD_CHECKOUT_DIR_FINAL=$SD_CHECKOUT_DIR; fi && echo 'Cloning github.com/screwdriver-cd/guide, on branch branchName' && if [ ! -z $GIT_SHALLOW_CLONE ] && [ $GIT_SHALLOW_CLONE = false ]; then $SD_GIT_WRAPPER \"git clone --recursive --quiet --progress --branch 'branchName' $SCM_URL $SD_CHECKOUT_DIR_FINAL\"; else if [ ! -z \"$GIT_SHALLOW_CLONE_SINCE\" ]; then export GIT_SHALLOW_CLONE_DEPTH_OPTION=\"--shallow-since='$GIT_SHALLOW_CLONE_SINCE'\"; else if [ -z $GIT_SHALLOW_CLONE_DEPTH ]; then export GIT_SHALLOW_CLONE_DEPTH=50; fi; export GIT_SHALLOW_CLONE_DEPTH_OPTION=\"--depth=$GIT_SHALLOW_CLONE_DEPTH\"; fi; export GIT_SHALLOW_CLONE_BRANCH=\"--no-single-branch\"; if [ \"$GIT_SHALLOW_CLONE_SINGLE_BRANCH\" = true ]; then export GIT_SHALLOW_CLONE_BRANCH=\"\"; fi; $SD_GIT_WRAPPER \"git clone $GIT_SHALLOW_CLONE_DEPTH_OPTION $GIT_SHALLOW_CLONE_BRANCH --recursive --quiet --progress --branch 'branchName' $SCM_URL $SD_CHECKOUT_DIR_FINAL\"; fi && $SD_GIT_WRAPPER \"git reset --hard '12345' --\" && echo 'Reset to 12345' && export GIT_BRANCH='origin/branchName' && $SD_GIT_WRAPPER \"git submodule init\" && $SD_GIT_WRAPPER \"git submodule update --recursive\""
}
4 changes: 4 additions & 0 deletions test/data/readOnlyCommandsSsh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "sd-checkout-code",
"command": "export SD_GIT_WRAPPER=\"$(if [ `uname` = 'Darwin' ]; then echo 'eval'; else echo 'sd-step exec core/git'; fi)\" && if [ ! -z $SD_SCM_DEPLOY_KEY ]; then export SCM_CLONE_TYPE=ssh; fi && echo Exporting environment variables && export SCM_URL=git@github.com:screwdriver-cd/guide && export GIT_URL=$SCM_URL.git && export GIT_MERGE_AUTOEDIT=no && if [ ! -z $SD_SCM_DEPLOY_KEY ] && [ $SCM_CLONE_TYPE = ssh ]; then echo $SD_SCM_DEPLOY_KEY | base64 -d > /tmp/git_key && echo \"\" >> /tmp/git_key && chmod 600 /tmp/git_key && export GIT_SSH_COMMAND=\"ssh -i /tmp/git_key\" && mkdir -p ~/.ssh/ && printf \"%s\n\" \"CiAgICAgICAgSG9zdCBnaXRodWIuY29tCiAgICAgICAgICAgIFN0cmljdEhvc3RLZXlDaGVja2luZyBubwogICAgICAgIA==\" | base64 -d >> ~/.ssh/config; fi && echo Setting user name and user email && $SD_GIT_WRAPPER \"git config --global user.name sd-buildbot\" && $SD_GIT_WRAPPER \"git config --global user.email dev-null@screwdriver.cd\" && export SD_CHECKOUT_DIR_FINAL=$SD_SOURCE_DIR && if [ ! -z $SD_CHECKOUT_DIR ]; then export SD_CHECKOUT_DIR_FINAL=$SD_CHECKOUT_DIR; fi && echo 'Cloning github.com/screwdriver-cd/guide, on branch branchName' && if [ ! -z $GIT_SHALLOW_CLONE ] && [ $GIT_SHALLOW_CLONE = false ]; then $SD_GIT_WRAPPER \"git clone --recursive --quiet --progress --branch 'branchName' $SCM_URL $SD_CHECKOUT_DIR_FINAL\"; else if [ ! -z \"$GIT_SHALLOW_CLONE_SINCE\" ]; then export GIT_SHALLOW_CLONE_DEPTH_OPTION=\"--shallow-since='$GIT_SHALLOW_CLONE_SINCE'\"; else if [ -z $GIT_SHALLOW_CLONE_DEPTH ]; then export GIT_SHALLOW_CLONE_DEPTH=50; fi; export GIT_SHALLOW_CLONE_DEPTH_OPTION=\"--depth=$GIT_SHALLOW_CLONE_DEPTH\"; fi; export GIT_SHALLOW_CLONE_BRANCH=\"--no-single-branch\"; if [ \"$GIT_SHALLOW_CLONE_SINGLE_BRANCH\" = true ]; then export GIT_SHALLOW_CLONE_BRANCH=\"\"; fi; $SD_GIT_WRAPPER \"git clone $GIT_SHALLOW_CLONE_DEPTH_OPTION $GIT_SHALLOW_CLONE_BRANCH --recursive --quiet --progress --branch 'branchName' $SCM_URL $SD_CHECKOUT_DIR_FINAL\"; fi && $SD_GIT_WRAPPER \"git reset --hard '12345' --\" && echo 'Reset to 12345' && export GIT_BRANCH='origin/branchName' && $SD_GIT_WRAPPER \"git submodule init\" && $SD_GIT_WRAPPER \"git submodule update --recursive\""
}
39 changes: 39 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const testPayloadBadAction = require('./data/github.pull_request.badAction.json'
const testPayloadPing = require('./data/github.ping.json');
const testPayloadPingBadSshHost = require('./data/github.ping.badSshHost.json');
const testCommands = require('./data/commands.json');
const testReadOnlyCommandsSsh = require('./data/readOnlyCommandsSsh.json');
const testReadOnlyCommandsHttps = require('./data/readOnlyCommandsHttps.json');
const testPrCommands = require('./data/prCommands.json');
const testForkPrCommands = require('./data/forkPrCommands.json');
const testCustomPrCommands = require('./data/customPrCommands.json');
Expand Down Expand Up @@ -110,6 +112,7 @@ describe('index', function () {
minTimeout: 1
}
},
readOnly: {},
oauthClientId: 'abcdefg',
oauthClientSecret: 'hijklmno',
secret: 'somesecret',
Expand Down Expand Up @@ -208,6 +211,42 @@ describe('index', function () {
})
);

it('gets the checkout command with https clone type when read-only is enabled', () => {
scm = new GithubScm({
oauthClientId: 'abcdefg',
oauthClientSecret: 'hijklmno',
gheHost: 'github.screwdriver.cd',
secret: 'somesecret',
readOnly: {
enabled: true,
cloneType: 'https'
}
});

return scm.getCheckoutCommand(config)
.then((command) => {
assert.deepEqual(command, testReadOnlyCommandsHttps);
});
});

it('gets the checkout command with ssh clone type when read-only is enabled', () => {
scm = new GithubScm({
oauthClientId: 'abcdefg',
oauthClientSecret: 'hijklmno',
gheHost: 'github.screwdriver.cd',
secret: 'somesecret',
readOnly: {
enabled: true,
cloneType: 'ssh'
}
});

return scm.getCheckoutCommand(config)
.then((command) => {
assert.deepEqual(command, testReadOnlyCommandsSsh);
});
});

it('promises to get the checkout command for a pull request', () => {
config.prRef = 'pull/3/merge';

Expand Down

0 comments on commit 8cbd8ac

Please sign in to comment.