向OAuth授权的GitHub仓库注入Secret时的密钥及加密库问题
GitHub仓库Secret注入问题及修复方案
问题描述
尝试向已通过OAuth 2.0授权的用户仓库注入GitHub Secret变量(已获取用户access token),使用Octokit创建4096位Deploy Key,再按文档要求用Sodium库加密Secret值,但遇到以下问题:
- 若部署密钥设为32字节,GitHub报错密钥过短;
- 若设为4096位,加密时提示密钥长度错误(应为32字节);
- 使用其他加密库时,GitHub提示必须使用Sodium,不支持其他库。
原问题代码
async function generatePublicKey():Promise<string> { return new Promise( (resolve, reject) => { generateKeyPair('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'pkcs1', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem', } }, (err, publicKey, privateKey) => { if(err){ reject(err) } else{ const pemKey = sshpk.parseKey(publicKey, 'pem'); const sshRsa = pemKey.toString('ssh'); console.log("ssh key is : ",sshRsa); resolve(sshRsa); } }); } ); } async injectSecretIntoRepository(repository: string, owner: string, accessToken: string, secretName: string, secretValue: string) { const octokit = new Octokit({ auth: accessToken }); console.debug("finding deploy key") const deployKeysResponse = await octokit.rest.repos.listDeployKeys({ owner, repo: repository }); // Find the deploy key with write access let deployKey = deployKeysResponse.data.find((key) =>( key.read_only === false )); console.warn(`deploy key: ${JSON.stringify( deployKeysResponse.data)}`) if (!deployKey) { console.warn(`Creating a new deploy key: `) try{ const key = await generatePublicKey() deployKey =( await octokit.rest.repos.createDeployKey({ owner, repo: repository, title: 'Componly deploy key', key, read_only: false, })).data; console.warn(`Deploy key created ${JSON.stringify(deployKey)}`) }catch(err){ console.warn(`failed to create a new deploy key`+err) throw new InternalServerErrorException(err) } } try { const sodium = await SodiumPlus.auto() //@ts-ignore const secretKey = CryptographyKey.from(deployKey.key) const nonce = await sodium.randombytes_buf(sodium.CRYPTO_BOX_NONCEBYTES) //@ts-ignore const encryptedValue = await sodium.crypto_secretbox (secretValue,nonce,secretKey) // Create or update the secret with the encrypted value await octokit.rest.actions.createOrUpdateRepoSecret({ owner, repo: repository, secret_name: secretName, encrypted_value:encryptedValue.toString("base64") }); console.log("Secret injected successfully."); } catch (err) { console.error("Error injecting secret:", err); throw new InternalServerErrorException("Failed to inject secret into the repository."); } }
核心错误原因
混淆了Deploy Key和GitHub仓库加密公钥的用途:
- Deploy Key是用于SSH拉取/推送仓库代码的RSA密钥,长度要求4096位,和Secret加密无关;
- 加密GitHub Secret需要使用GitHub为每个仓库生成的专属非对称加密公钥,而非自行生成的Deploy Key,该公钥是32字节的Curve25519格式,符合Sodium的加密要求。
修复方案
步骤1:获取仓库的加密公钥
调用Octokit的actions.getRepoPublicKey接口,获取GitHub提供的仓库公钥及对应的key_id。
步骤2:使用Sodium加密Secret值
用crypto_box_seal方法(非对称加密,无需nonce)对Secret值加密,该方法专门用于用公钥加密只有对应私钥能解密的内容。
步骤3:更新Secret接口调用
传入获取到的key_id和加密后的base64值到createOrUpdateRepoSecret接口。
修正后的代码
async injectSecretIntoRepository(repository: string, owner: string, accessToken: string, secretName: string, secretValue: string) { const octokit = new Octokit({ auth: accessToken }); try { // 1. 获取仓库的加密公钥(核心:不是Deploy Key) const { data: publicKeyData } = await octokit.rest.actions.getRepoPublicKey({ owner, repo: repository }); const sodium = await SodiumPlus.auto(); // 解析GitHub提供的公钥(base64格式) const publicKey = await sodium.crypto_box_seal_open_publickey(Buffer.from(publicKeyData.key, 'base64')); // 2. 加密Secret值:用crypto_box_seal,无需nonce const encryptedBuffer = await sodium.crypto_box_seal(secretValue, publicKey); const encryptedValue = encryptedBuffer.toString('base64'); // 3. 创建/更新Secret,传入key_id await octokit.rest.actions.createOrUpdateRepoSecret({ owner, repo: repository, secret_name: secretName, encrypted_value: encryptedValue, key_id: publicKeyData.key_id }); console.log("Secret injected successfully."); } catch (err) { console.error("Error injecting secret:", err); throw new InternalServerErrorException("Failed to inject secret into the repository."); } }
额外说明
- 无需自行生成任何密钥(包括Deploy Key),除非你需要用SSH操作仓库代码;
crypto_box_seal是GitHub官方推荐的加密方式,完全符合Sodium库要求,不会出现密钥长度不匹配的问题;- 确保你的access token拥有
repo权限(用于操作仓库Secret)。
内容的提问来源于stack exchange,提问作者dark man
相关产品推荐
相关产品推荐

