使用带有秘密的 github 操作反应应用程序构建/部署

Posted

技术标签:

【中文标题】使用带有秘密的 github 操作反应应用程序构建/部署【英文标题】:React app build/deploy using github actions with secrets 【发布时间】:2020-12-03 12:27:51 【问题描述】:

我正在尝试使用带有秘密的 github 操作来完成构建/部署我的使用 Firebase(目前只有身份验证模块)的反应应用程序。 对于本地开发,我使用带有 webpack 和 dotenv-webpack 库的 .env 文件。在本地机器上一切正常。开发服务器从 .env 文件中获取环境变量并注入它。但是在构建 github 操作并在 firebase 托管页面上部署包后返回一个错误:

code: "auth/invalid-api-key"
message: "Your API key is invalid, please check you have copied it correctly."

经过一番调查,我发现环境变量没有正确定义:

apiKey: undefined
authDomain: undefined
databaseURL: undefined
messagingSenderId: undefined
projectId: undefined
storageBucket: undefined

主要问题是我是否正确地进行了变量注入,或者是否有其他方法可以做到这一点? 我在构建中使用的 webpack 配置:

webpack.build.conf.js

const  merge  = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');

const buildWebpackConfig = merge(baseWebpackConfig, 
  //!!!
  //CAUTION Production config
  //!!!
  mode: 'production',
);

module.exports = new Promise((resolve, reject) => 
  resolve(buildWebpackConfig);
);

webpack.base.conf.js

const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const Dotenv = require('dotenv-webpack');

module.exports = 
  entry: './src/index.js',
  output: 
    path: path.resolve(__dirname, 'build'),
    publicPath: '/',
    filename: 'bundle.min.js',
  ,
  resolve: 
    extensions: ['.js', '.jsx'],
    alias: 
      '@constants': path.resolve(__dirname, './src/constants'),
      '@components': path.resolve(__dirname, './src/components'),
      '@utils': path.resolve(__dirname, './src/utils'),
      '@styles': path.resolve(__dirname, './src/style'),
    ,
  ,
  module: 
    rules: [
      
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader', 'eslint-loader'],
      ,
      
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader'],
      ,
    ],
  ,
  plugins: [
    new HtmlWebpackPlugin(
      template: path.resolve('./index.html'),
    ),
    new Dotenv(),
  ],
;

从 .env 文件中获取变量的文件:

//Firebase config
export const FB_API_KEY = process.env.REACT_APP_API_FB_KEY;
export const FB_AUTH_DOMAIN = process.env.REACT_APP_FB_AUTH_DOMAIN;
export const FB_DATABASE_URL = process.env.REACT_APP_FB_DATABASE_URL;
export const FB_PROJECT_ID = process.env.REACT_APP_FB_PROJECT_ID;
export const FB_STORAGE_BUCKET = process.env.REACT_APP_STORAGE_BUCKET;
export const FB_MESSAGING_SENDER_ID = process.env.REACT_APP_FB_MESSAGING_SENDER_ID;

管道文件:

name: Firebase Deploy
on:
  push:
    branches:
      - master
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
        env:
          REACT_APP_API_FB_KEY: $ secrets.REACT_APP_API_FB_KEY 
          REACT_APP_FB_AUTH_DOMAIN: $ secrets.REACT_APP_FB_AUTH_DOMAIN 
          REACT_APP_FB_DATABASE_URL: $ secrets.REACT_APP_FB_DATABASE_URL 
          REACT_APP_FB_PROJECT_ID: $ secrets.FB_PROJECT_ID 
          REACT_APP_FB_STORAGE_BUCKET: $ secrets.FB_STORAGE_BUCKET 
          REACT_APP_FB_MESSAGING_SENDER_ID: $ secrets.FB_MESSAGING_SENDER_ID 
      - name: Variable to dotenv
          uses: CallePuzzle/envvar-to-dotenv-action@0.1.0
          with:
            variableNamesByFilter: ^REACT_(APP.*)
      - name: Install Dependencies
        run: npm install
      - name: Build
        run: npm run build
      - name: Archive Production Artifact
        uses: actions/upload-artifact@master
        with:
          name: build
          path: build
  deploy:
    name: Deploy
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
      - name: Download Artifact
        uses: actions/download-artifact@master
        with:
          name: build
          path: build
      - name: Deploy to Firebase
        uses: w9jds/firebase-action@master
        with:
          args: deploy --only hosting
        env:
          FIREBASE_TOKEN: $ secrets.FIREBASE_TOKEN 

【问题讨论】:

【参考方案1】:
name: Firebase Deploy
on:
  push:
    branches:
      - master

env:
  REACT_APP_API_FB_KEY: $ secrets.REACT_APP_API_FB_KEY 
  REACT_APP_FB_AUTH_DOMAIN: $ secrets.REACT_APP_FB_AUTH_DOMAIN 
  REACT_APP_FB_DATABASE_URL: $ secrets.REACT_APP_FB_DATABASE_URL 
  REACT_APP_FB_PROJECT_ID: $ secrets.FB_PROJECT_ID 
  REACT_APP_FB_STORAGE_BUCKET: $ secrets.FB_STORAGE_BUCKET 
  REACT_APP_FB_MESSAGING_SENDER_ID: $ secrets.FB_MESSAGING_SENDER_ID 

obs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
...

env 部分移至顶层怎么样?目前env 仅受检出步骤影响,检出无关紧要,因为将 env 注入源代码处于构建阶段。

或者您可以在构建步骤中传递 env。

【讨论】:

谢谢你的回答,但我也试过了。在我的情况下它不起作用。现在我尝试添加空白 .env 文件并附加变量。但这也没有用。 我以为你使用 create-react-app 因为你在环境中使用 REACT_APP_ 前缀。但似乎你自己有 webpack 配置。它是否正确? 1.如果我是正确的,通常我们直接在.env中写入值并在源代码中使用process.env.REACT_APP_API_FB_KEY。 2. 在某些情况下我使用 webpack.DefinePlugin 将 env 传递给源代码。 是的,我正在使用 .env 文件进行开发。使用 dotenv-webpack 插件。但对于生产,我想使用 github 机密,所以我不需要在代表中存储有价值的密钥。【参考方案2】:

我找到了解决方案。问题出在 Webpack 配置中。 Webpack 似乎需要在编译时定义环境变量。为此我使用了webpack.DefinePlugin

webpack.build.conf.js

const  merge  = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');
const webpack = require('webpack');

const buildWebpackConfig = merge(baseWebpackConfig, 
  //!!!
  //CAUTION Production config
  //!!!
  mode: 'production',
  plugins: [
    new webpack.DefinePlugin(
      'process.env': 
        REACT_APP_API_FB_KEY: JSON.stringify(process.env.REACT_APP_API_FB_KEY),
        REACT_APP_FB_AUTH_DOMAIN: JSON.stringify(process.env.REACT_APP_FB_AUTH_DOMAIN),
        REACT_APP_FB_DATABASE_URL: JSON.stringify(process.env.REACT_APP_FB_DATABASE_URL),
        REACT_APP_FB_PROJECT_ID: JSON.stringify(process.env.REACT_APP_FB_PROJECT_ID),
        REACT_APP_STORAGE_BUCKET: JSON.stringify(process.env.REACT_APP_STORAGE_BUCKET),
        REACT_APP_FB_MESSAGING_SENDER_ID: JSON.stringify(process.env.REACT_APP_FB_MESSAGING_SENDER_ID),
      ,
    ),
  ],
);

module.exports = new Promise((resolve, reject) => 
  resolve(buildWebpackConfig);
);

并且不需要附加 .env 文件。在 process.env 中完美传递的变量:

name: Firebase Deploy
on:
  push:
    branches:
      - master
env:
  REACT_APP_API_FB_KEY: $ secrets.REACT_APP_API_FB_KEY 
  REACT_APP_FB_AUTH_DOMAIN: $ secrets.REACT_APP_FB_AUTH_DOMAIN 
  REACT_APP_FB_DATABASE_URL: $ secrets.REACT_APP_FB_DATABASE_URL 
  REACT_APP_FB_PROJECT_ID: $ secrets.FB_PROJECT_ID 
  REACT_APP_FB_STORAGE_BUCKET: $ secrets.FB_STORAGE_BUCKET 
  REACT_APP_FB_MESSAGING_SENDER_ID: $ secrets.FB_MESSAGING_SENDER_ID 
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Debug Action
        uses: hmarr/debug-action@v1.0.0
      - name: Checkout Repo
        uses: actions/checkout@master
      - name: Install Dependencies
        run: npm install
      - name: Build
        run: npm run build
      - name: Archive Production Artifact
        uses: actions/upload-artifact@master
        with:
          name: build
          path: build
  deploy:
    name: Deploy
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
      - name: Download Artifact
        uses: actions/download-artifact@master
        with:
          name: build
          path: build
      - name: Deploy to Firebase
        uses: w9jds/firebase-action@master
        with:
          args: deploy --only hosting
        env:
          FIREBASE_TOKEN: $ secrets.FIREBASE_TOKEN 

非常感谢。

【讨论】:

以上是关于使用带有秘密的 github 操作反应应用程序构建/部署的主要内容,如果未能解决你的问题,请参考以下文章

使用 GitHub 操作部署反应应用程序的问题

应用程序不会通过 docker build 从 github 检索秘密

从 golang 脚本中检索带有空格的 Github 机密

Django 设置和 GitHub 操作秘密

GitHub的秘密扫描功能可能暴露PyPI和RubyGems的密码

如何在 GitHub Actions 中构建的 Dockerfile 中使用 github 令牌并尝试克隆私有存储库?