gogithub-actions-runners

Retrieving Github secrets with spaces from golang script


I would like to retrieve a Github secret content from a script via Golang, that is executed from Github actions. In this particular situation, the secret value stored in Github secrets has a space. I mean the secret value is: JWT <token-string>.

The way to retrieve Github secrets from any script in any language as long they are executed in Github actions runners is by reading them as environment variables. So what I am doing is to read it in this way: (Please see the Authorization: element in the slice of string below)

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": []string{os.Getenv("USER_JWT")},
    }

The thing is that I am not getting the value from Github secrets when running Github action runner. I know this is happening since I tried to print it in this way, but nothing comes up:

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

I am afraid it is happening because that space between "JWT " and the token, I mean JWT <token-string>.

Here says:

Secret names can only contain alphanumeric characters ([a-z], [A-Z], [0-9]) or underscores (_). Spaces are not allowed.

As an important fact, my token secret value also contains . character in its value. The value is something like this:

JWT xxxxxxx8888xxxxdsdsfsfsf9.eyJxxxxxxx8888xxxxdsdsfsfsf9.Tfgxadsdsfsfsasasad_s7sdsdsfgsgcs

So I believe, that is the reason why I cannot get the secret value.

I am not sure how I can fetch this from my Golang script, I even tried to modify the Github secret value just having it as a value the <token-string> in order to avoid the space in the value, and I am calling it from go in this way:

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

But it did not work. I read here that when calling secrets with special characters from github actions we have to escape them with single quotes ' ' but this process is from .yaml file github actions.

The previous solution alternatives I am trying to, they works on my local machine, since my bash cli is able to get environment variables with spaces in their values. I am not sure how can I - let's say "escape" - a secret with space in a string as I have from golang.


Solution

  • I managed to read the JWT secret stored in GitHub secrets from a GitHub action executing the golang terratest code.

    As mentioned, since Github secrets does not allow spaces " " and dots . characters and the token has some dots plus one space, that I did first was to encode it

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

    This generates a whole string without . or spaces and then I stored this value on Github secrets. And I read it from golang in this way:

    
    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)
    }
    
    

    But in addition as @WishwaPerera try to tell me, the new environment variable i am using from golang called SPECKLE_USER_JWT_ENCODE above, has to be included in my github actions at the moment to run these tests from go test command. So my github action .yaml file finally is in this way:

    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
    

    A nice reference to understand a bit how to handle the HTTP package