Skip to content

Commit 4da6246

Browse files
chore(release): 1.3.0 [skip ci]
# [1.3.0](v1.2.0...v1.3.0) (2023-06-15) ### Features * **actions:** validate response when checking active deployment ([2619917](2619917)) * **deps:** bump @semantic-release/changelog from 6.0.2 to 6.0.3 ([ed92b3b](ed92b3b)) * **deps:** bump dotenv from 16.0.3 to 16.1.0 ([b7651e0](b7651e0)) * **deps:** bump dotenv from 16.1.0 to 16.1.3 ([3613c30](3613c30)) * **deps:** bump dotenv from 16.1.3 to 16.1.4 ([90ab6c7](90ab6c7)) * **deps:** bump node-fetch from 3.3.0 to 3.3.1 ([4c68b89](4c68b89))
1 parent 2619917 commit 4da6246

File tree

3 files changed

+227
-25
lines changed

3 files changed

+227
-25
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
# [1.3.0](https://github.com/sws2apps/render-deployment/compare/v1.2.0...v1.3.0) (2023-06-15)
2+
3+
4+
### Features
5+
6+
* **actions:** validate response when checking active deployment ([2619917](https://github.com/sws2apps/render-deployment/commit/261991795f627d139361f38e45a8b279aadff160))
7+
* **deps:** bump @semantic-release/changelog from 6.0.2 to 6.0.3 ([ed92b3b](https://github.com/sws2apps/render-deployment/commit/ed92b3b34a859f372cbcc55a2e0c192d9c3fff3e))
8+
* **deps:** bump dotenv from 16.0.3 to 16.1.0 ([b7651e0](https://github.com/sws2apps/render-deployment/commit/b7651e0bb1dd491c73878c25c3cdbf6792d917ca))
9+
* **deps:** bump dotenv from 16.1.0 to 16.1.3 ([3613c30](https://github.com/sws2apps/render-deployment/commit/3613c308bf1c9121bcb9a6015163909c2e207164))
10+
* **deps:** bump dotenv from 16.1.3 to 16.1.4 ([90ab6c7](https://github.com/sws2apps/render-deployment/commit/90ab6c793bd5950a6555b4f02982af1ac307b6e9))
11+
* **deps:** bump node-fetch from 3.3.0 to 3.3.1 ([4c68b89](https://github.com/sws2apps/render-deployment/commit/4c68b89f763d7b88df04588c910262ec7fa94f8f))
12+
113
# [1.2.0](https://github.com/sws2apps/render-deployment/compare/v1.1.0...v1.2.0) (2023-02-12)
214

315

dist/index.js

Lines changed: 214 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1819,13 +1819,14 @@ module.exports = options
18191819
const fs = __nccwpck_require__(7147)
18201820
const path = __nccwpck_require__(1017)
18211821
const os = __nccwpck_require__(2037)
1822+
const crypto = __nccwpck_require__(6113)
18221823
const packageJson = __nccwpck_require__(9968)
18231824

18241825
const version = packageJson.version
18251826

18261827
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
18271828

1828-
// Parser src into an Object
1829+
// Parse src into an Object
18291830
function parse (src) {
18301831
const obj = {}
18311832

@@ -1864,20 +1865,130 @@ function parse (src) {
18641865
return obj
18651866
}
18661867

1868+
function _parseVault (options) {
1869+
const vaultPath = _vaultPath(options)
1870+
1871+
// Parse .env.vault
1872+
const result = DotenvModule.configDotenv({ path: vaultPath })
1873+
if (!result.parsed) {
1874+
throw new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`)
1875+
}
1876+
1877+
// handle scenario for comma separated keys - for use with key rotation
1878+
// example: DOTENV_KEY="dotenv://:[email protected]/vault/.env.vault?environment=prod,dotenv://:[email protected]/vault/.env.vault?environment=prod"
1879+
const keys = _dotenvKey().split(',')
1880+
const length = keys.length
1881+
1882+
let decrypted
1883+
for (let i = 0; i < length; i++) {
1884+
try {
1885+
// Get full key
1886+
const key = keys[i].trim()
1887+
1888+
// Get instructions for decrypt
1889+
const attrs = _instructions(result, key)
1890+
1891+
// Decrypt
1892+
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key)
1893+
1894+
break
1895+
} catch (error) {
1896+
// last key
1897+
if (i + 1 >= length) {
1898+
throw error
1899+
}
1900+
// try next key
1901+
}
1902+
}
1903+
1904+
// Parse decrypted .env string
1905+
return DotenvModule.parse(decrypted)
1906+
}
1907+
18671908
function _log (message) {
1909+
console.log(`[dotenv@${version}][INFO] ${message}`)
1910+
}
1911+
1912+
function _warn (message) {
1913+
console.log(`[dotenv@${version}][WARN] ${message}`)
1914+
}
1915+
1916+
function _debug (message) {
18681917
console.log(`[dotenv@${version}][DEBUG] ${message}`)
18691918
}
18701919

1920+
function _dotenvKey () {
1921+
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
1922+
return process.env.DOTENV_KEY
1923+
}
1924+
1925+
return ''
1926+
}
1927+
1928+
function _instructions (result, dotenvKey) {
1929+
// Parse DOTENV_KEY. Format is a URI
1930+
let uri
1931+
try {
1932+
uri = new URL(dotenvKey)
1933+
} catch (error) {
1934+
if (error.code === 'ERR_INVALID_URL') {
1935+
throw new Error('INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:[email protected]/vault/.env.vault?environment=development')
1936+
}
1937+
1938+
throw error
1939+
}
1940+
1941+
// Get decrypt key
1942+
const key = uri.password
1943+
if (!key) {
1944+
throw new Error('INVALID_DOTENV_KEY: Missing key part')
1945+
}
1946+
1947+
// Get environment
1948+
const environment = uri.searchParams.get('environment')
1949+
if (!environment) {
1950+
throw new Error('INVALID_DOTENV_KEY: Missing environment part')
1951+
}
1952+
1953+
// Get ciphertext payload
1954+
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`
1955+
const ciphertext = result.parsed[environmentKey] // DOTENV_VAULT_PRODUCTION
1956+
if (!ciphertext) {
1957+
throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`)
1958+
}
1959+
1960+
return { ciphertext, key }
1961+
}
1962+
1963+
function _vaultPath (options) {
1964+
let dotenvPath = path.resolve(process.cwd(), '.env')
1965+
1966+
if (options && options.path && options.path.length > 0) {
1967+
dotenvPath = options.path
1968+
}
1969+
1970+
// Locate .env.vault
1971+
return dotenvPath.endsWith('.vault') ? dotenvPath : `${dotenvPath}.vault`
1972+
}
1973+
18711974
function _resolveHome (envPath) {
18721975
return envPath[0] === '~' ? path.join(os.homedir(), envPath.slice(1)) : envPath
18731976
}
18741977

1875-
// Populates process.env from .env file
1876-
function config (options) {
1978+
function _configVault (options) {
1979+
_log('Loading env from encrypted .env.vault')
1980+
1981+
const parsed = DotenvModule._parseVault(options)
1982+
1983+
DotenvModule.populate(process.env, parsed, options)
1984+
1985+
return { parsed }
1986+
}
1987+
1988+
function configDotenv (options) {
18771989
let dotenvPath = path.resolve(process.cwd(), '.env')
18781990
let encoding = 'utf8'
18791991
const debug = Boolean(options && options.debug)
1880-
const override = Boolean(options && options.override)
18811992

18821993
if (options) {
18831994
if (options.path != null) {
@@ -1892,41 +2003,115 @@ function config (options) {
18922003
// Specifying an encoding returns a string instead of a buffer
18932004
const parsed = DotenvModule.parse(fs.readFileSync(dotenvPath, { encoding }))
18942005

1895-
Object.keys(parsed).forEach(function (key) {
1896-
if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
1897-
process.env[key] = parsed[key]
1898-
} else {
1899-
if (override === true) {
1900-
process.env[key] = parsed[key]
1901-
}
1902-
1903-
if (debug) {
1904-
if (override === true) {
1905-
_log(`"${key}" is already defined in \`process.env\` and WAS overwritten`)
1906-
} else {
1907-
_log(`"${key}" is already defined in \`process.env\` and was NOT overwritten`)
1908-
}
1909-
}
1910-
}
1911-
})
2006+
DotenvModule.populate(process.env, parsed, options)
19122007

19132008
return { parsed }
19142009
} catch (e) {
19152010
if (debug) {
1916-
_log(`Failed to load ${dotenvPath} ${e.message}`)
2011+
_debug(`Failed to load ${dotenvPath} ${e.message}`)
19172012
}
19182013

19192014
return { error: e }
19202015
}
19212016
}
19222017

2018+
// Populates process.env from .env file
2019+
function config (options) {
2020+
const vaultPath = _vaultPath(options)
2021+
2022+
// fallback to original dotenv if DOTENV_KEY is not set
2023+
if (_dotenvKey().length === 0) {
2024+
return DotenvModule.configDotenv(options)
2025+
}
2026+
2027+
// dotenvKey exists but .env.vault file does not exist
2028+
if (!fs.existsSync(vaultPath)) {
2029+
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`)
2030+
2031+
return DotenvModule.configDotenv(options)
2032+
}
2033+
2034+
return DotenvModule._configVault(options)
2035+
}
2036+
2037+
function decrypt (encrypted, keyStr) {
2038+
const key = Buffer.from(keyStr.slice(-64), 'hex')
2039+
let ciphertext = Buffer.from(encrypted, 'base64')
2040+
2041+
const nonce = ciphertext.slice(0, 12)
2042+
const authTag = ciphertext.slice(-16)
2043+
ciphertext = ciphertext.slice(12, -16)
2044+
2045+
try {
2046+
const aesgcm = crypto.createDecipheriv('aes-256-gcm', key, nonce)
2047+
aesgcm.setAuthTag(authTag)
2048+
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`
2049+
} catch (error) {
2050+
const isRange = error instanceof RangeError
2051+
const invalidKeyLength = error.message === 'Invalid key length'
2052+
const decryptionFailed = error.message === 'Unsupported state or unable to authenticate data'
2053+
2054+
if (isRange || invalidKeyLength) {
2055+
const msg = 'INVALID_DOTENV_KEY: It must be 64 characters long (or more)'
2056+
throw new Error(msg)
2057+
} else if (decryptionFailed) {
2058+
const msg = 'DECRYPTION_FAILED: Please check your DOTENV_KEY'
2059+
throw new Error(msg)
2060+
} else {
2061+
console.error('Error: ', error.code)
2062+
console.error('Error: ', error.message)
2063+
throw error
2064+
}
2065+
}
2066+
}
2067+
2068+
// Populate process.env with parsed values
2069+
function populate (processEnv, parsed, options = {}) {
2070+
const debug = Boolean(options && options.debug)
2071+
const override = Boolean(options && options.override)
2072+
2073+
if (typeof parsed !== 'object') {
2074+
throw new Error('OBJECT_REQUIRED: Please check the processEnv argument being passed to populate')
2075+
}
2076+
2077+
// Set process.env
2078+
for (const key of Object.keys(parsed)) {
2079+
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
2080+
if (override === true) {
2081+
processEnv[key] = parsed[key]
2082+
}
2083+
2084+
if (debug) {
2085+
if (override === true) {
2086+
_debug(`"${key}" is already defined and WAS overwritten`)
2087+
} else {
2088+
_debug(`"${key}" is already defined and was NOT overwritten`)
2089+
}
2090+
}
2091+
} else {
2092+
processEnv[key] = parsed[key]
2093+
}
2094+
}
2095+
}
2096+
19232097
const DotenvModule = {
2098+
configDotenv,
2099+
_configVault,
2100+
_parseVault,
19242101
config,
1925-
parse
2102+
decrypt,
2103+
parse,
2104+
populate
19262105
}
19272106

2107+
module.exports.configDotenv = DotenvModule.configDotenv
2108+
module.exports._configVault = DotenvModule._configVault
2109+
module.exports._parseVault = DotenvModule._parseVault
19282110
module.exports.config = DotenvModule.config
2111+
module.exports.decrypt = DotenvModule.decrypt
19292112
module.exports.parse = DotenvModule.parse
2113+
module.exports.populate = DotenvModule.populate
2114+
19302115
module.exports = DotenvModule
19312116

19322117

@@ -7753,7 +7938,7 @@ return new B(c,{type:"multipart/form-data; boundary="+b})}
77537938
/***/ 9968:
77547939
/***/ ((module) => {
77557940

7756-
module.exports = JSON.parse('{"name":"dotenv","version":"16.0.3","description":"Loads environment variables from .env file","main":"lib/main.js","types":"lib/main.d.ts","exports":{".":{"require":"./lib/main.js","types":"./lib/main.d.ts","default":"./lib/main.js"},"./config":"./config.js","./config.js":"./config.js","./lib/env-options":"./lib/env-options.js","./lib/env-options.js":"./lib/env-options.js","./lib/cli-options":"./lib/cli-options.js","./lib/cli-options.js":"./lib/cli-options.js","./package.json":"./package.json"},"scripts":{"dts-check":"tsc --project tests/types/tsconfig.json","lint":"standard","lint-readme":"standard-markdown","pretest":"npm run lint && npm run dts-check","test":"tap tests/*.js --100 -Rspec","prerelease":"npm test","release":"standard-version"},"repository":{"type":"git","url":"git://github.com/motdotla/dotenv.git"},"keywords":["dotenv","env",".env","environment","variables","config","settings"],"readmeFilename":"README.md","license":"BSD-2-Clause","devDependencies":{"@types/node":"^17.0.9","decache":"^4.6.1","dtslint":"^3.7.0","sinon":"^12.0.1","standard":"^16.0.4","standard-markdown":"^7.1.0","standard-version":"^9.3.2","tap":"^15.1.6","tar":"^6.1.11","typescript":"^4.5.4"},"engines":{"node":">=12"}}');
7941+
module.exports = JSON.parse('{"name":"dotenv","version":"16.1.4","description":"Loads environment variables from .env file","main":"lib/main.js","types":"lib/main.d.ts","exports":{".":{"types":"./lib/main.d.ts","require":"./lib/main.js","default":"./lib/main.js"},"./config":"./config.js","./config.js":"./config.js","./lib/env-options":"./lib/env-options.js","./lib/env-options.js":"./lib/env-options.js","./lib/cli-options":"./lib/cli-options.js","./lib/cli-options.js":"./lib/cli-options.js","./package.json":"./package.json"},"scripts":{"dts-check":"tsc --project tests/types/tsconfig.json","lint":"standard","lint-readme":"standard-markdown","pretest":"npm run lint && npm run dts-check","test":"tap tests/*.js --100 -Rspec","prerelease":"npm test","release":"standard-version"},"repository":{"type":"git","url":"git://github.com/motdotla/dotenv.git"},"funding":"https://github.com/motdotla/dotenv?sponsor=1","keywords":["dotenv","env",".env","environment","variables","config","settings"],"readmeFilename":"README.md","license":"BSD-2-Clause","devDependencies":{"@definitelytyped/dtslint":"^0.0.133","@types/node":"^18.11.3","decache":"^4.6.1","sinon":"^14.0.1","standard":"^17.0.0","standard-markdown":"^7.1.0","standard-version":"^9.5.0","tap":"^16.3.0","tar":"^6.1.11","typescript":"^4.8.4"},"engines":{"node":">=12"},"browser":{"fs":false}}');
77577942

77587943
/***/ })
77597944

@@ -10104,6 +10289,11 @@ const run = async () => {
1010410289
res = await fetch(`https://api.render.com/v1/services/${serviceId}/deploys?limit=20`, { method: 'GET', ...options });
1010510290
data = await res.json();
1010610291

10292+
if (!data) {
10293+
core.setFailed(`This operation did not succeed. Please check if the serviceId and apiKey inputs were correclty set`);
10294+
return;
10295+
}
10296+
1010710297
if (res.status !== 200) {
1010810298
core.setFailed(`This operation did not succeed. Reason: ${data.message}`);
1010910299
return;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "render-deployment",
33
"description": "A GitHub Action to trigger deployment in Render.",
4-
"version": "1.2.0",
4+
"version": "1.3.0",
55
"private": true,
66
"type": "module",
77
"homepage": "https://github.com/sws2apps/render-deployment#readme",

0 commit comments

Comments
 (0)