@cloudbase/cli
Advanced tools
| /* eslint-disable */ | ||
| var runtime = require('./runtime') | ||
| var util = require('util') | ||
| var initHandlerFault = 'function initialization failed' | ||
| var maxRetMsgLen = 6 * 1024 * 1024 // byte | ||
| var maxRetMsgLenExceedError = 'body size is too long' | ||
| var httpHandler, eventHandler | ||
| var _result, _fault | ||
| var _user_exception = false | ||
| function wrapLog(invokeId) { | ||
| console.log = console.info = function prettyConsoleLog() { | ||
| var message = `${util.format.apply(this, arguments)}` | ||
| runtime.console_log(message) | ||
| } | ||
| console.error = console.warn = function prettyConsoleLogErr() { | ||
| var message = `${util.format.apply(this, arguments)}` | ||
| runtime.console_log(message, (err = true)) | ||
| } | ||
| } | ||
| function main() { | ||
| if (0 != runtime.init()) { | ||
| console.log('runtime init failed') | ||
| return | ||
| } | ||
| runtime.log('init succ') | ||
| cleanEnv() | ||
| process.on('beforeExit', () => { | ||
| runtime.log('catch exit') | ||
| finish(null, null, false) | ||
| }) | ||
| process.on('uncaughtException', err => { | ||
| runtime.log('catch exception') | ||
| finish(err, null, false) | ||
| }) | ||
| waitForInvoke() | ||
| } | ||
| function cleanEnv() { | ||
| var envToDelete = ['SOCKETPATH', 'CONTAINERID'] | ||
| for (var k in process.env) { | ||
| if (k.startsWith('KUBERNETES')) { | ||
| envToDelete.push(k) | ||
| } | ||
| } | ||
| envToDelete.forEach(e => { | ||
| delete process.env[e] | ||
| }) | ||
| } | ||
| function waitForInvoke() { | ||
| runtime.log('wait for invoke') | ||
| var invokeInfo = runtime.wait_for_invoke() | ||
| setTimeout(() => { | ||
| runtime.log('timed out, invoke') | ||
| invoke(invokeInfo) | ||
| }, 0) | ||
| } | ||
| function invoke(invokeInfo) { | ||
| if (invokeInfo.cmd === 'RELOAD') { | ||
| runtime.log(`get reload request: ${invokeInfo.context}`) | ||
| // 路径中可能包含 . 符号 | ||
| var ff = invokeInfo.globalHandler.split('.') | ||
| initHandler(invokeInfo.filePath + ff[0], ff[1]) | ||
| runtime.log('handlers reloaded') | ||
| _result = 'reload' | ||
| finish(null, null, false) | ||
| return | ||
| } | ||
| _result = undefined | ||
| _fault = undefined | ||
| runtime.report_running() | ||
| var ev, ctx | ||
| if (invokeInfo.event || invokeInfo.context) { | ||
| try { | ||
| ev = JSON.parse(invokeInfo.event) | ||
| ctx = JSON.parse(invokeInfo.context) | ||
| } catch (err) { | ||
| _fault = `eval event[${invokeInfo.event}] or context [${invokeInfo.context}] failed\n${err}` | ||
| return | ||
| } | ||
| } | ||
| ctx['environ'].split(';').forEach(e => { | ||
| if (e == '') return | ||
| var kv = e.split('=', 2) | ||
| process.env[kv[0]] = kv[1] | ||
| }) | ||
| runtime.log(`request[${ctx['request_id']}] invoked`) | ||
| if (!httpHandler && !eventHandler) { | ||
| _fault = initHandlerFault | ||
| return | ||
| } | ||
| wrapLog(ctx['request_id']) | ||
| if (invokeInfo.cmd === 'HTTP') { | ||
| httpHandler.handle(invokeInfo.sockfd) | ||
| } else if (invokeInfo.cmd === 'EVENT') { | ||
| eventHandler.handle(ev, ctx) | ||
| } else { | ||
| _fault = `recv unknown task type: ${invokeInfo.cmd}` | ||
| runtime.log(`recv unknown task type: ${invokeInfo.cmd}`) | ||
| } | ||
| runtime.log('process finished') | ||
| } | ||
| function initHandler(file, func) { | ||
| try { | ||
| var path = require('path') | ||
| var current_path = path.dirname(file) | ||
| process.chdir(current_path) | ||
| runtime.log(`working directory: ${process.cwd()}`) | ||
| for (var item in require.cache) { | ||
| delete require.cache[item] | ||
| } | ||
| var usermod = require(file) | ||
| httpHandler = new HttpHandler(usermod[func]) | ||
| eventHandler = new EventHandler(usermod[func]) | ||
| } catch (err) { | ||
| runtime.log(`get user function[${file}:${func}] failed`) | ||
| runtime.log(err.stack) | ||
| initHandlerFault = err.message | ||
| _user_exception = true | ||
| } | ||
| } | ||
| function finish(err, data, wait) { | ||
| runtime.log('finish') | ||
| runtime.log(wait ? 'wait' : 'not wait') | ||
| if (_result === undefined) { | ||
| if (err == null) { | ||
| try { | ||
| _result = JSON.stringify(data === undefined ? null : data) | ||
| } catch (err) { | ||
| _result = 'faulted' | ||
| _fault = `stringify response to json failed: ${err.message}` | ||
| return | ||
| } | ||
| } else { | ||
| _result = 'faulted' | ||
| if (err instanceof Error) { | ||
| runtime.console_log(err.stack, true) | ||
| _fault = err.message | ||
| } else { | ||
| var errStr = String(err) | ||
| _fault = `${errStr}(callback err is not instance of Error)` | ||
| } | ||
| } | ||
| } | ||
| if (wait) { | ||
| return | ||
| } | ||
| runtime.log(_result) | ||
| process.nextTick(() => { | ||
| if (_result == 'reload') { | ||
| // reload response, do nothing | ||
| } else if (_fault !== undefined) { | ||
| _user_exception = true | ||
| var errType = _user_exception ? 2 : 1 | ||
| runtime.report_fail(_fault, 0, errType) | ||
| } else if (_result.length > maxRetMsgLen) { | ||
| runtime.report_fail(maxRetMsgLenExceedError, 0, 1) | ||
| } else { | ||
| runtime.report_done(_result, 0) | ||
| } | ||
| waitForInvoke() | ||
| }) | ||
| } | ||
| class HttpHandler { | ||
| constructor(func) { | ||
| this.realHandler = func | ||
| } | ||
| handle(fd) {} | ||
| } | ||
| class EventHandler { | ||
| constructor(func) { | ||
| this.realHandler = func | ||
| } | ||
| handle(ev, ctx) { | ||
| var called = false | ||
| var wait = true | ||
| var callback = (err, data) => { | ||
| if (called) { | ||
| return | ||
| } | ||
| called = true | ||
| finish(err, data, wait) | ||
| } | ||
| var ctxx = Object.assign( | ||
| { | ||
| set callbackWaitsForEmptyEventLoop(value) { | ||
| wait = value | ||
| }, | ||
| get callbackWaitsForEmptyEventLoop() { | ||
| return wait | ||
| }, | ||
| getContext() { | ||
| return ctx | ||
| }, | ||
| done: function(err, data) { | ||
| wait = false | ||
| callback(err, data) | ||
| }, | ||
| succeed: function(data) { | ||
| ctxx.done(null, data) | ||
| }, | ||
| fail: function(err) { | ||
| ctxx.done(err, null) | ||
| } | ||
| }, | ||
| ctx | ||
| ) | ||
| try { | ||
| _user_exception = false | ||
| var ret = this.realHandler(ev, ctxx, callback) | ||
| if ( | ||
| ret && | ||
| ret.then !== undefined && | ||
| typeof ret.then === 'function' | ||
| ) { | ||
| ret.then(ctxx.succeed, ctxx.fail) | ||
| } | ||
| } catch (err) { | ||
| runtime.console_log(err.stack, true) | ||
| _fault = err.stack | ||
| _user_exception = true | ||
| } | ||
| } | ||
| } | ||
| main() |
| /* eslint-disable */ | ||
| const fs = require('fs') | ||
| const crypto = require('crypto') | ||
| var GLOBAL_FUNCTION_HANDLER = process.argv[2] || process.env.SCF_FUNCTION_HANDLER || 'index.main' | ||
| var GLOBAL_FUNCTION_NAME = process.env.SCF_FUNCTION_NAME || 'main' | ||
| var GLOBAL_EVENT_BODY = | ||
| process.argv[3] || | ||
| process.env.SCF_EVENT_BODY || | ||
| (process.env.DOCKER_USE_STDIN && fs.readFileSync('/dev/stdin', 'utf8')) || | ||
| '{}' | ||
| var GLOBAL_USER_FILE_PATH = process.env.GLOBAL_USER_FILE_PATH || '' | ||
| var GLOBAL_VERSION = process.env.SCF_FUNCTION_VERSION || '$LATEST' | ||
| var GLOBAL_MEM_SIZE = process.env.SCF_FUNCTION_MEMORY_SIZE || '256' | ||
| var GLOBAL_TIMEOUT = process.env.SCF_FUNCTION_TIMEOUT || '3' | ||
| var GLOBAL_ENVIRON = process.env.SCF_FUNCTION_ENVIRON || '' | ||
| var GLOBAL_IS_QUIET = process.env.SCF_DISPLAY_IS_QUIET === 'True' || false | ||
| var GLOBAL_REQUEST_ID = uuid() | ||
| var GLOBAL_START_TIME = process.hrtime() | ||
| var GLOBAL_SOCK = -1 | ||
| var GLOBAL_STAGE = 0 | ||
| module.exports = { | ||
| init: function() { | ||
| if (!GLOBAL_IS_QUIET) { | ||
| consoleLog('开始本地执行云函数,受环境影响,执行结果可能与云端存在一定差异!') | ||
| consoleLog('START RequestId: ' + GLOBAL_REQUEST_ID) | ||
| } | ||
| return 0 | ||
| }, | ||
| wait_for_invoke: function() { | ||
| var invokeInfo = [] | ||
| GLOBAL_STAGE += 1 | ||
| switch (GLOBAL_STAGE) { | ||
| case 1: | ||
| invokeInfo.cmd = 'RELOAD' | ||
| invokeInfo.context = GLOBAL_USER_FILE_PATH + GLOBAL_FUNCTION_HANDLER | ||
| invokeInfo.globalHandler = GLOBAL_FUNCTION_HANDLER | ||
| invokeInfo.filePath = GLOBAL_USER_FILE_PATH | ||
| break | ||
| case 2: | ||
| invokeInfo.cmd = 'EVENT' | ||
| invokeInfo.sockfd = GLOBAL_SOCK | ||
| invokeInfo.event = GLOBAL_EVENT_BODY | ||
| invokeInfo.context = initContext() | ||
| break | ||
| default: | ||
| process.exit() | ||
| } | ||
| return invokeInfo | ||
| }, | ||
| log: function(str) { | ||
| // consoleLog(formatSystem(str)) | ||
| }, | ||
| console_log: function(str, err = false) { | ||
| if (!GLOBAL_IS_QUIET) { | ||
| if (err === false) { | ||
| consoleLog(formatConsole(str)) | ||
| } else { | ||
| consoleLogErr(formatConsole(str)) | ||
| } | ||
| } | ||
| }, | ||
| report_fail: function(stackTrace, errNum, errType = 0) { | ||
| const result = {} | ||
| result['errorCode'] = 1 | ||
| result['errorMessage'] = 'user code exception caught' | ||
| if (stackTrace) { | ||
| result['stackTrace'] = stackTrace | ||
| } | ||
| reportDone('', (errType = 1)) | ||
| // console.dir(result); | ||
| consoleLogErr(JSON.stringify(result)) | ||
| }, | ||
| report_running: function() { | ||
| GLOBAL_START_TIME = process.hrtime() | ||
| }, | ||
| report_done: function(resultStr, errType = 0) { | ||
| reportDone(resultStr, errType) | ||
| } | ||
| } | ||
| function initContext() { | ||
| var context = {} | ||
| context['function_version'] = GLOBAL_VERSION | ||
| context['function_name'] = GLOBAL_FUNCTION_NAME | ||
| context['time_limit_in_ms'] = GLOBAL_TIMEOUT | ||
| context['memory_limit_in_mb'] = GLOBAL_MEM_SIZE | ||
| context['request_id'] = GLOBAL_REQUEST_ID | ||
| context['environ'] = GLOBAL_ENVIRON | ||
| return JSON.stringify(context) | ||
| } | ||
| function reportDone(resultStr, errType = 0) { | ||
| if (GLOBAL_IS_QUIET) { | ||
| if (typeof resultStr === 'string') { | ||
| if (errType === 0) consoleLog(resultStr) | ||
| else consoleLogErr(resultStr) | ||
| } | ||
| return | ||
| } | ||
| var diffMs = hrTimeMs(process.hrtime(GLOBAL_START_TIME)) | ||
| var billedMs = Math.min(100 * (Math.floor(diffMs / 100) + 1), GLOBAL_TIMEOUT * 1000) | ||
| if (errType === 0) { | ||
| consoleLog('END RequestId: ' + GLOBAL_REQUEST_ID) | ||
| consoleLog( | ||
| [ | ||
| '运行信息:', | ||
| 'REPORT RequestId: ' + GLOBAL_REQUEST_ID, | ||
| 'Duration: ' + diffMs.toFixed(2) + ' ms', | ||
| 'Billed Duration: ' + billedMs + ' ms', | ||
| 'Memory Size: ' + GLOBAL_MEM_SIZE + ' MB', | ||
| 'Max Memory Used: ' + Math.round(process.memoryUsage().rss / (1024 * 1024)) + ' MB' | ||
| ].join('\n') | ||
| ) | ||
| } else { | ||
| consoleLogErr( | ||
| [ | ||
| '运行信息:', | ||
| 'REPORT RequestId: ' + GLOBAL_REQUEST_ID, | ||
| 'Duration: ' + diffMs.toFixed(2) + ' ms', | ||
| 'Billed Duration: ' + billedMs + ' ms', | ||
| 'Memory Size: ' + GLOBAL_MEM_SIZE + ' MB', | ||
| 'Max Memory Used: ' + Math.round(process.memoryUsage().rss / (1024 * 1024)) + ' MB' | ||
| ].join('\n') | ||
| ) | ||
| } | ||
| if (typeof resultStr === 'string') { | ||
| if (errType === 0) { | ||
| consoleLog('返回结果:\n' + resultStr) | ||
| } else { | ||
| consoleLogErr('返回结果:\n' + resultStr) | ||
| } | ||
| } | ||
| } | ||
| function consoleLog(str) { | ||
| process.stdout.write(str + '\n') | ||
| } | ||
| function consoleLogErr(str) { | ||
| process.stderr.write(str + '\n') | ||
| } | ||
| function formatConsole(str) { | ||
| return str.replace(/^[0-9TZ:.-]+\t[0-9a-f-]+\t/, '\u001b[34m$&\u001b[0m') | ||
| } | ||
| function formatSystem(str) { | ||
| return '\u001b[32m' + str + '\u001b[0m' | ||
| } | ||
| function hrTimeMs(hrtime) { | ||
| return (hrtime[0] * 1e9 + hrtime[1]) / 1e6 | ||
| } | ||
| function uuid() { | ||
| return ( | ||
| crypto.randomBytes(4).toString('hex') + | ||
| '-' + | ||
| crypto.randomBytes(2).toString('hex') + | ||
| '-' + | ||
| crypto | ||
| .randomBytes(2) | ||
| .toString('hex') | ||
| .replace(/^./, '1') + | ||
| '-' + | ||
| crypto.randomBytes(2).toString('hex') + | ||
| '-' + | ||
| crypto.randomBytes(6).toString('hex') | ||
| ) | ||
| } |
+3
-2
| { | ||
| "name": "@cloudbase/cli", | ||
| "version": "3.0.0-alpha.9", | ||
| "version": "3.0.0-alpha.10", | ||
| "description": "CLI for Tencent CloudBase (standalone bundle)", | ||
@@ -14,5 +14,6 @@ "bin": { | ||
| "dist/standalone", | ||
| "dist/fonts" | ||
| "dist/fonts", | ||
| "runtime/nodejs" | ||
| ], | ||
| "license": "ISC" | ||
| } |
+30
-0
@@ -45,4 +45,34 @@ # CloudBase 命令行工具  | ||
| ## 退出码说明 | ||
| CloudBase CLI 使用结构化退出码帮助 CI/CD 流水线和 AI Agent 精确处理错误: | ||
| | 退出码 | 含义 | 典型场景 | 应对策略 | | ||
| |--------|------|----------|----------| | ||
| | 0 | 成功 | 命令正常执行 | - | | ||
| | 1 | 通用错误 | 未分类的异常 | 查看错误信息,手动排查 | | ||
| | 2 | 认证失败 | 未登录、token 过期、无权限 | 执行 `tcb login` 重新登录 | | ||
| | 3 | 参数错误 | 缺少必填参数、格式非法、枚举值错误 | 检查命令参数,参考 `tcb <cmd> --help` | | ||
| | 4 | 资源不存在 | 环境 ID/函数名无效、集合不存在 | 确认资源名称,用 `tcb env list` / `tcb fn list` 验证 | | ||
| | 5 | 云 API 错误 | CloudBase API 返回错误、网络超时 | 检查网络连接,查看 API 错误详情,必要时重试 | | ||
| | 6 | 本地文件错误 | cloudbaserc.json 缺失/损坏、路径不存在 | 检查配置文件,用 `tcb init` 重新初始化 | | ||
| **CI/CD 脚本示例**: | ||
| ```bash | ||
| # 根据退出码自动重试 | ||
| tcb fn deploy || { | ||
| code=$? | ||
| case $code in | ||
| 2) echo "Auth failed, retrying..." && tcb login && tcb fn deploy ;; | ||
| 5) echo "API error, retrying in 30s..." && sleep 30 && tcb fn deploy ;; | ||
| *) echo "Unrecoverable error (code $code)" && exit $code ;; | ||
| esac | ||
| } | ||
| ``` | ||
| 完整定义参见:[src/exit-codes.ts](./src/exit-codes.ts) | ||
| ## 意见反馈 | ||
| 您可以到 GitHub Repo 新建一个 [issue](https://github.com/TencentCloudBase/cloudbase-cli/issues) 反馈您在使用过程中遇到的问题或建议。 |
Sorry, the diff of this file is too big to display
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 11 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
37204222
0.77%12
20%80386
0.48%78
62.5%17
750%