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

Posted

技术标签:

【中文标题】从 golang 脚本中检索带有空格的 Github 机密【英文标题】:Retrieving Github secrets with spaces from golang script 【发布时间】:2021-09-11 03:28:23 【问题描述】:

我想通过 Golang 从脚本中检索 Github 机密内容,该脚本是通过 Github 操作执行的。 在这种特殊情况下,存储在 Github secrets 中的秘密值有一个空格。我的意思是秘密值是:JWT <token-string>

从任何语言的任何脚本中检索 Github 机密(只要它们在 Github 操作运行器中执行)的方法是将它们作为环境变量读取。所以我要做的就是这样读:(请看下面字符串切片中的Authorization:元素)

func MyTestFunction(t *testing.T, serverURL string) 

    type AppLogin struct 
        token string
    
    method := "GET"

    
    headers := map[string][]string
        "Content-Type": []string"application/json, text/plain, */*",
        "Authorization": []stringos.Getenv("USER_JWT"),
    

问题是我在运行 Github action runner 时没有从 Github secrets 中获得价值。我知道这种情况正在发生,因为我尝试以这种方式打印它,但没有任何结果:

fmt.Println("My JWT", os.Getenv("USER_JWT"))

我担心它正在发生,因为"JWT " 和令牌之间的空间,我的意思是JWT <token-string>

Here 说:

秘密名称只能包含字母数字字符([a-z]、[A-Z]、[0-9])或下划线 (_)。 不允许使用空格。

作为一个重要的事实,我的令牌秘密值还包含. 字符。值是这样的:

JWT xxxxxxx8888xxxxdsdsfsfsf9.eyJxxxxxxx8888xxxxdsdsfsfsf9.Tfgxadsdsfsfsasasad_s7sdsdsfgsgcs

所以我相信,这就是我无法获得秘密值的原因。

我不确定如何从我的 Golang 脚本中获取它,我什至尝试修改 Github 机密值,只是将其作为值 <token-string> 以避免值中的空格,我正在调用它以这种方式运行:

"Authorization": []string"JWT ", os.Getenv("SPECKLE_USER_JWT")

但它没有工作。 我读到here,当从 github 操作中调用带有特殊字符的秘密时,我们必须用单引号 ' ' 转义它们,但这个过程来自 .yaml 文件 github 操作。

我正在尝试的以前的解决方案替代方案,它们适用于我的本地机器,因为我的 bash cli 能够获取值中带有空格的环境变量。我不知道我怎么能 - 让我们说“转义” - 一个字符串中有空格的秘密,就像我从 golang 得到的那样。

【问题讨论】:

你也可以显示工作流 yaml 吗? @WishwaPerera,因为 go 代码是一个测试,所以从 GitHub 操作 YAML 文件我只是执行 go test 命令来启动该过程。 @WishwaPerera 你的提示是对的,我错过了在我的 github 操作 yaml 文件中调用秘密变量。 :D 【参考方案1】:

我设法从执行 golang terratest 代码的 GitHub 操作中读取了存储在 GitHub 机密中的 JWT 机密。

如前所述,由于 Github 机密不允许空格 " " 和点 . 字符,并且令牌有一些点加一个空格,所以我首先要做的是对其进行编码

echo -n '<token-value>' | base64

这会生成一个没有. 或空格的完整字符串,然后我将此值存储在 Github 机密中。我是这样从golang中读取的:


func main() 
   var t *testing.T
   serverURL := os.Getenv("SERVER_URL")
   MyTestFunction(t, serverURL)


func MyTestFunction(t *testing.T, serverURL string) 

    type SpeckleLogin struct 
        token string
    
    method := "GET"

    // The encoded token is read from github secrets
    b64EncodeJwt := os.Getenv("USER_JWT_ENCODE")
    // fmt.Println("The encode JWT is:", b64EncodeJwt)

    // The encoded read token is decoded
    b64DecodeJwt, _ := b64.StdEncoding.DecodeString(b64EncodeJwt)
    // fmt.Println("JWT Decoded", string(b64DecodeJwt))
    // fmt.Println()
    
    headers := map[string][]string
        "Content-Type": []string"application/json, text/plain, */*",
        
        // The content of the token already decoded is included in the headers slice of strings. 
        "Authorization": []string(string(b64DecodeJwt)),
    


    jsonLogin := []byte(fmt.Sprintf(`
        "email":"%s",
        "password": "%s"
    `, os.Getenv("USER_EMAIL"), os.Getenv("USER_PASSWORD")))
    
    // The HTTP request is created
    reqLogin, errReq := http.NewRequest(method, serverURL+"/api/accounts", bytes.NewBuffer(jsonLogin))

    // The headers are added to the HTTP request
    reqLogin.Header = headers

    if errReq != nil 
        messageReq := fmt.Sprintf("Error GET login request: %s", errReq.Error())
        t.Fatal(messageReq)
    

    clientLogin := &http.Client
        Transport: &http.Transport
            TLSClientConfig: &tls.Config
                InsecureSkipVerify: true,
            ,
        ,
    
    // Sending the request
    respLogin, errResp := clientLogin.Do(reqLogin)

    if errResp != nil 
        messageResp := fmt.Sprintf("Error GET login response: %s", errResp.Error())
        t.Fatal(messageResp)
    

    defer respLogin.Body.Close()

    body, _ := ioutil.ReadAll(respLogin.Body)

    // fmt.Println("BODY IS:")
    // fmt.Println(string(body))

    var speckleLogin map[string]interface

    if err := json.Unmarshal([]byte(body), &speckleLogin); err != nil 
        t.Fatal("Could not unmarshal json")
    

    // We take the API token from the response
    data := speckleLogin["resource"].(map[string]interface)["apitoken"]   

    if speckleToken, ok := data.(string); ok 

        // Here we assert the token is not empty
        assert.NotEmpty(t, speckleToken)


但除了@WishwaPerera 试图告诉我,我在上面使用的名为SPECKLE_USER_JWT_ENCODE 的golang 新环境变量必须包含在我的github 操作中,以便从go test 命令运行这些测试.所以我的github action.yaml文件最后是这样的:

name: Preview_Workflow

on:
  pull_request:
    branches:
    - master

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - name: 'Checkout GitHub Action'
      uses: actions/checkout@master

    - name: Install terraform 
      uses: hashicorp/setup-terraform@v1
      with:
        terraform_version: 0.13.5
        terraform_wrapper: false

    - name: 'Terraform Version'
      shell: bash
      run: |
        terraform version

    - name: 'Login via Azure CLI'
      uses: azure/login@v1
      with:
        creds: $ secrets.AZURE_CREDENTIALS 

    - name: 'Setup Go'
      id: go
      uses: actions/setup-go@v2
      with:
        go-version: '^1.16.5'

    - name: 'Run Terratest'
      id: terratest
      run: |
        cd tests
        go get -u github.com/Azure/azure-storage-blob-go/azblob
        go get -u github.com/gruntwork-io/terratest/modules/terraform
        go get -u github.com/stretchr/testify/assert
        // executing the test
        go test
      env:
        SERVER_URL: "https://my-service-application-url"
        USER_EMAIL: $ secrets.USER_EMAIL 
        USER_PASSWORD: $ secrets.USER_PASSWORD 
        USER_JWT_ENCODE: $ secrets.USER_JWT_ENCODE 

        # I am using these other ones to connect to azure.
        ARM_CLIENT_ID: $ secrets.ARM_CLIENT_ID 
        ARM_CLIENT_SECRET: $ secrets.ARM_CLIENT_SECRET 
        ARM_SUBSCRIPTION_ID: $ secrets.ARM_SUBSCRIPTION_ID 
        ARM_TENANT_ID: $ secrets.ARM_TENANT_ID 

    - name: Azure logout
      run: |
        az logout

一个很好的参考理解一点how to handle the HTTP package

【讨论】:

以上是关于从 golang 脚本中检索带有空格的 Github 机密的主要内容,如果未能解决你的问题,请参考以下文章

在文件路径中运行带有空格的 PowerShell 脚本

将带有空格的路径作为参数传递给 bat 文件

c# - 如何从忽略字符串空格的列表中检索字符串元素?

ADF - 带有 powershell 脚本的管道

如何在 Go (Golang) 中检索表单数据作为地图(如 PHP 和 Ruby)

shell脚本传递带有空格的参数的解决方法