Skip to content

Commit 643bc80

Browse files
Michael BahrJosh Barr
Michael Bahr
and
Josh Barr
authoredMar 16, 2023
🐛 Make repo, user and branch url safe (#289)
* fix: slugify repo and branch * chore: linting * fix: param case user * chore: comment * chore: comment * chore: formatting * feat: output unique deployment url * fix: get deployment url with protocol * feat: handle long branch urls * feat: add logging * chore: debug * feat: logs * fix: must be 63 chars * fix: b64url * fix: b64url * fix: digest to hex * chore: info to warning * chore: remove editorconfig and prettier file * chore: update lockfile * chore: add back action-input-parser * chore: improve regex * chore: cleanup --------- Co-authored-by: Josh Barr <josh.barr@stedi.com>
1 parent 39ad2e1 commit 643bc80

File tree

3 files changed

+82
-18
lines changed

3 files changed

+82
-18
lines changed
 

‎action.yml

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ outputs:
9595
description: 'True if a comment was created on the PR or commit.'
9696
DEPLOYMENT_INSPECTOR_URL:
9797
description: 'Main deployment inspection url.'
98+
DEPLOYMENT_UNIQUE_URL:
99+
description: 'The unique deployment url on Vercel'
98100

99101
runs:
100102
using: 'node16'

‎dist/index.js

+40-9
Original file line numberDiff line numberDiff line change
@@ -16550,6 +16550,7 @@ const core = __nccwpck_require__(2186)
1655016550
const Github = __nccwpck_require__(8396)
1655116551
const Vercel = __nccwpck_require__(847)
1655216552
const { addSchema } = __nccwpck_require__(8505)
16553+
const crypto = __nccwpck_require__(6113)
1655316554

1655416555
const {
1655516556
GITHUB_DEPLOYMENT,
@@ -16571,6 +16572,9 @@ const {
1657116572
ACTOR
1657216573
} = __nccwpck_require__(4570)
1657316574

16575+
// Following https://perishablepress.com/stop-using-unsafe-characters-in-urls/ only allow characters that won't break the URL.
16576+
const urlSafeParameter = (input) => input.replace(/[^a-z0-9_~]/gi, '-')
16577+
1657416578
const run = async () => {
1657516579
const github = Github.init()
1657616580

@@ -16616,27 +16620,53 @@ const run = async () => {
1661616620
if (IS_PR && PR_PREVIEW_DOMAIN) {
1661716621
core.info(`Assigning custom preview domain to PR`)
1661816622

16619-
const alias = PR_PREVIEW_DOMAIN
16620-
.replace('{USER}', USER)
16621-
.replace('{REPO}', REPOSITORY)
16622-
.replace('{BRANCH}', BRANCH)
16623+
if (typeof PR_PREVIEW_DOMAIN !== 'string') {
16624+
throw new Error(`invalid type for PR_PREVIEW_DOMAIN`)
16625+
}
16626+
16627+
const alias = PR_PREVIEW_DOMAIN.replace('{USER}', urlSafeParameter(USER))
16628+
.replace('{REPO}', urlSafeParameter(REPOSITORY))
16629+
.replace('{BRANCH}', urlSafeParameter(BRANCH))
1662316630
.replace('{PR}', PR_NUMBER)
1662416631
.replace('{SHA}', SHA.substring(0, 7))
1662516632
.toLowerCase()
1662616633

16627-
await vercel.assignAlias(alias)
16634+
const previewDomainSuffix = '.vercel.app'
16635+
let nextAlias = alias
16636+
16637+
16638+
if (alias.endsWith(previewDomainSuffix)) {
16639+
let prefix = alias.substring(0, alias.indexOf(previewDomainSuffix))
16640+
16641+
if (prefix.length >= 60) {
16642+
core.warning(`The alias ${ prefix } exceeds 60 chars in length, truncating using vercel's rules. See https://vercel.com/docs/concepts/deployments/automatic-urls#automatic-branch-urls`)
16643+
prefix = prefix.substring(0, 55)
16644+
const uniqueSuffix = crypto.createHash('sha256')
16645+
.update(`git-${ BRANCH }-${ REPOSITORY }`)
16646+
.digest('hex')
16647+
.slice(0, 6)
1662816648

16629-
deploymentUrls.push(addSchema(alias))
16649+
nextAlias = `${ prefix }-${ uniqueSuffix }${ previewDomainSuffix }`
16650+
core.info(`Updated domain alias: ${ nextAlias }`)
16651+
}
16652+
}
16653+
16654+
await vercel.assignAlias(nextAlias)
16655+
deploymentUrls.push(addSchema(nextAlias))
1663016656
}
1663116657

1663216658
if (!IS_PR && ALIAS_DOMAINS) {
1663316659
core.info(`Assigning custom domains to Vercel deployment`)
1663416660

16661+
if (!Array.isArray(ALIAS_DOMAINS)) {
16662+
throw new Error(`invalid type for PR_PREVIEW_DOMAIN`)
16663+
}
16664+
1663516665
for (let i = 0; i < ALIAS_DOMAINS.length; i++) {
1663616666
const alias = ALIAS_DOMAINS[i]
16637-
.replace('{USER}', USER)
16638-
.replace('{REPO}', REPOSITORY)
16639-
.replace('{BRANCH}', BRANCH)
16667+
.replace('{USER}', urlSafeParameter(USER))
16668+
.replace('{REPO}', urlSafeParameter(REPOSITORY))
16669+
.replace('{BRANCH}', urlSafeParameter(BRANCH))
1664016670
.replace('{SHA}', SHA.substring(0, 7))
1664116671
.toLowerCase()
1664216672

@@ -16702,6 +16732,7 @@ const run = async () => {
1670216732

1670316733
core.setOutput('PREVIEW_URL', previewUrl)
1670416734
core.setOutput('DEPLOYMENT_URLS', deploymentUrls)
16735+
core.setOutput('DEPLOYMENT_UNIQUE_URL', deploymentUrls[deploymentUrls.length - 1])
1670516736
core.setOutput('DEPLOYMENT_ID', deployment.id)
1670616737
core.setOutput('DEPLOYMENT_INSPECTOR_URL', deployment.inspectorUrl)
1670716738
core.setOutput('DEPLOYMENT_CREATED', true)

‎src/index.js

+40-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const core = require('@actions/core')
22
const Github = require('./github')
33
const Vercel = require('./vercel')
44
const { addSchema } = require('./helpers')
5+
const crypto = require('crypto')
56

67
const {
78
GITHUB_DEPLOYMENT,
@@ -23,6 +24,9 @@ const {
2324
ACTOR
2425
} = require('./config')
2526

27+
// Following https://perishablepress.com/stop-using-unsafe-characters-in-urls/ only allow characters that won't break the URL.
28+
const urlSafeParameter = (input) => input.replace(/[^a-z0-9_~]/gi, '-')
29+
2630
const run = async () => {
2731
const github = Github.init()
2832

@@ -68,27 +72,53 @@ const run = async () => {
6872
if (IS_PR && PR_PREVIEW_DOMAIN) {
6973
core.info(`Assigning custom preview domain to PR`)
7074

71-
const alias = PR_PREVIEW_DOMAIN
72-
.replace('{USER}', USER)
73-
.replace('{REPO}', REPOSITORY)
74-
.replace('{BRANCH}', BRANCH)
75+
if (typeof PR_PREVIEW_DOMAIN !== 'string') {
76+
throw new Error(`invalid type for PR_PREVIEW_DOMAIN`)
77+
}
78+
79+
const alias = PR_PREVIEW_DOMAIN.replace('{USER}', urlSafeParameter(USER))
80+
.replace('{REPO}', urlSafeParameter(REPOSITORY))
81+
.replace('{BRANCH}', urlSafeParameter(BRANCH))
7582
.replace('{PR}', PR_NUMBER)
7683
.replace('{SHA}', SHA.substring(0, 7))
7784
.toLowerCase()
7885

79-
await vercel.assignAlias(alias)
86+
const previewDomainSuffix = '.vercel.app'
87+
let nextAlias = alias
88+
89+
90+
if (alias.endsWith(previewDomainSuffix)) {
91+
let prefix = alias.substring(0, alias.indexOf(previewDomainSuffix))
8092

81-
deploymentUrls.push(addSchema(alias))
93+
if (prefix.length >= 60) {
94+
core.warning(`The alias ${ prefix } exceeds 60 chars in length, truncating using vercel's rules. See https://vercel.com/docs/concepts/deployments/automatic-urls#automatic-branch-urls`)
95+
prefix = prefix.substring(0, 55)
96+
const uniqueSuffix = crypto.createHash('sha256')
97+
.update(`git-${ BRANCH }-${ REPOSITORY }`)
98+
.digest('hex')
99+
.slice(0, 6)
100+
101+
nextAlias = `${ prefix }-${ uniqueSuffix }${ previewDomainSuffix }`
102+
core.info(`Updated domain alias: ${ nextAlias }`)
103+
}
104+
}
105+
106+
await vercel.assignAlias(nextAlias)
107+
deploymentUrls.push(addSchema(nextAlias))
82108
}
83109

84110
if (!IS_PR && ALIAS_DOMAINS) {
85111
core.info(`Assigning custom domains to Vercel deployment`)
86112

113+
if (!Array.isArray(ALIAS_DOMAINS)) {
114+
throw new Error(`invalid type for PR_PREVIEW_DOMAIN`)
115+
}
116+
87117
for (let i = 0; i < ALIAS_DOMAINS.length; i++) {
88118
const alias = ALIAS_DOMAINS[i]
89-
.replace('{USER}', USER)
90-
.replace('{REPO}', REPOSITORY)
91-
.replace('{BRANCH}', BRANCH)
119+
.replace('{USER}', urlSafeParameter(USER))
120+
.replace('{REPO}', urlSafeParameter(REPOSITORY))
121+
.replace('{BRANCH}', urlSafeParameter(BRANCH))
92122
.replace('{SHA}', SHA.substring(0, 7))
93123
.toLowerCase()
94124

@@ -154,6 +184,7 @@ const run = async () => {
154184

155185
core.setOutput('PREVIEW_URL', previewUrl)
156186
core.setOutput('DEPLOYMENT_URLS', deploymentUrls)
187+
core.setOutput('DEPLOYMENT_UNIQUE_URL', deploymentUrls[deploymentUrls.length - 1])
157188
core.setOutput('DEPLOYMENT_ID', deployment.id)
158189
core.setOutput('DEPLOYMENT_INSPECTOR_URL', deployment.inspectorUrl)
159190
core.setOutput('DEPLOYMENT_CREATED', true)

0 commit comments

Comments
 (0)
Please sign in to comment.