Skip to content

Commit

Permalink
Add support for getting OIDC token (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
sethvargo committed Nov 12, 2021
1 parent ab8a0d7 commit a712c2e
Show file tree
Hide file tree
Showing 15 changed files with 303 additions and 212 deletions.
36 changes: 0 additions & 36 deletions .github/workflows/codeql.yml

This file was deleted.

21 changes: 7 additions & 14 deletions .github/workflows/lock.yml
Expand Up @@ -12,26 +12,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.

name: Lock closed
name: 'Lock closed'
on:
schedule:
- cron: '0 0 * * *'

jobs:
lock:
runs-on: ubuntu-latest
runs-on: 'ubuntu-latest'
steps:
- uses: dessant/lock-threads@v2
- uses: 'dessant/lock-threads@v2'
with:
github-token: '${{ github.token }}'
issue-lock-inactive-days: 14
issue-lock-comment: |-
This issue has been automatically locked since there has not been any
recent activity after it was closed. Please open a new issue for
related bugs.
pr-lock-inactive-days: 14
pr-lock-comment: |-
This pull request has been automatically locked since there has not
been any recent activity after it was closed. Please open a new
issue for related bugs.
issue-lock-inactive-days: 1
issue-lock-reason: 'resolved'
pr-lock-inactive-days: 1
pr-lock-reason: 'resolved'
42 changes: 0 additions & 42 deletions .github/workflows/stale.yml

This file was deleted.

37 changes: 22 additions & 15 deletions .github/workflows/test.yml
Expand Up @@ -12,47 +12,54 @@
# See the License for the specific language governing permissions and
# limitations under the License.

name: Test
name: 'Test'

on:
push:
branches:
- main
- 'main'
tags:
- '*'
pull_request:
branches:
- main
- 'main'

concurrency:
group: '${{ github.head_ref || github.ref }}'
cancel-in-progress: true

jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
os:
- 'ubuntu-latest'
- 'windows-latest'
- 'macos-latest'
go:
- '1.13'
- '1.14'
- '1.15'
- '1.16'
- '1.17'

runs-on: ubuntu-latest
runs-on: '${{ matrix.os }}'

steps:
- uses: actions/checkout@v2
- uses: 'actions/checkout@v2'

- uses: actions/setup-go@v2
- uses: 'actions/setup-go@v2'
with:
go-version: '${{ matrix.go }}'

- uses: actions/cache@v2
- uses: 'actions/cache@v2'
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
path: '~/go/pkg/mod'
key: '${{ matrix.os }}-go-${{ matrix.go }}-${{ hashFiles(''**/go.sum'') }}'
restore-keys: |
${{ runner.os }}-go-
- name: Lint
run: make fmtcheck staticcheck spellcheck
${{ matrix.os }}-go-${{ matrix.go }}
${{ matrix.os }}-go-
- name: Test
- name: 'Test'
run: make test-acc
42 changes: 13 additions & 29 deletions Makefile
@@ -1,37 +1,22 @@
VETTERS = "asmdecl,assign,atomic,bools,buildtag,cgocall,composites,copylocks,errorsas,httpresponse,loopclosure,lostcancel,nilfunc,printf,shift,stdmethods,structtag,tests,unmarshal,unreachable,unsafeptr,unusedresult"
GOFMT_FILES = $(shell go list -f '{{.Dir}}' ./...)

fmtcheck:
@command -v goimports > /dev/null 2>&1 || (cd tools && go get golang.org/x/tools/cmd/goimports)
@CHANGES="$$(goimports -d $(GOFMT_FILES))"; \
if [ -n "$${CHANGES}" ]; then \
echo "Unformatted (run goimports -w .):\n\n$${CHANGES}\n\n"; \
exit 1; \
fi
@# Annoyingly, goimports does not support the simplify flag.
@CHANGES="$$(gofmt -s -d $(GOFMT_FILES))"; \
if [ -n "$${CHANGES}" ]; then \
echo "Unformatted (run gofmt -s -w .):\n\n$${CHANGES}\n\n"; \
exit 1; \
fi
.PHONY: fmtcheck

spellcheck:
@command -v misspell > /dev/null 2>&1 || (cd tools && go get github.com/client9/misspell/cmd/misspell)
@misspell -locale="US" -error -source="text" **/*
.PHONY: spellcheck

staticcheck:
@command -v staticcheck > /dev/null 2>&1 || (cd tools && go get honnef.co/go/tools/cmd/staticcheck)
@staticcheck -checks="all" -tests $(GOFMT_FILES)
.PHONY: staticcheck
# Copyright 2020 The Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

test:
@go test \
-count=1 \
-short \
-timeout=5m \
-vet="${VETTERS}" \
./...
.PHONY: test

Expand All @@ -40,6 +25,5 @@ test-acc:
-count=1 \
-race \
-timeout=10m \
-vet="${VETTERS}" \
./...
.PHONY: test-acc
81 changes: 77 additions & 4 deletions actions.go
Expand Up @@ -18,11 +18,17 @@
package githubactions

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
"time"
)

var (
Expand Down Expand Up @@ -59,13 +65,21 @@ const (
// New creates a new wrapper with helpers for outputting information in GitHub
// actions format.
func New(opts ...Option) *Action {
a := &Action{w: os.Stdout, getenv: os.Getenv}
a := &Action{
w: os.Stdout,
getenv: os.Getenv,
httpClient: &http.Client{
Timeout: 10 * time.Second,
},
}

for _, opt := range opts {
if opt == nil {
continue
}
a = opt(a)
}

return a
}

Expand All @@ -81,9 +95,10 @@ func NewWithWriter(w io.Writer) *Action {
// Action is an internal wrapper around GitHub Actions' output and magic
// strings.
type Action struct {
w io.Writer
fields CommandProperties
getenv GetenvFunc
w io.Writer
fields CommandProperties
getenv GetenvFunc
httpClient *http.Client
}

// IssueCommand issues a new GitHub actions Command.
Expand Down Expand Up @@ -316,6 +331,64 @@ func (c *Action) WithFieldsMap(m map[string]string) *Action {
}
}

// idTokenResponse is the response from minting an ID token.
type idTokenResponse struct {
Value string `json:"value,omitempty"`
}

// GetIDToken returns the GitHub OIDC token from the GitHub Actions runtime.
func (c *Action) GetIDToken(ctx context.Context, audience string) (string, error) {
requestURL := c.getenv("ACTIONS_ID_TOKEN_REQUEST_URL")
if requestURL == "" {
return "", fmt.Errorf("missing ACTIONS_ID_TOKEN_REQUEST_URL in environment")
}

requestToken := c.getenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN")
if requestToken == "" {
return "", fmt.Errorf("missing ACTIONS_ID_TOKEN_REQUEST_TOKEN in environment")
}

u, err := url.Parse(requestURL)
if err != nil {
return "", fmt.Errorf("failed to parse request URL: %w", err)
}
if audience != "" {
q := u.Query()
q.Set("audience", audience)
u.RawQuery = q.Encode()
}

req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
if err != nil {
return "", fmt.Errorf("failed to create HTTP request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+requestToken)

resp, err := c.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("failed to make HTTP request: %w", err)
}
defer resp.Body.Close()

// This has moved to the io package in Go 1.16, but we still support up to Go
// 1.13 for now.
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 64*1000))
if err != nil {
return "", fmt.Errorf("failed to read response body: %w", err)
}
body = bytes.TrimSpace(body)

if resp.StatusCode != 200 {
return "", fmt.Errorf("non-successful response from minting OIDC token: %s", body)
}

var tokenResp idTokenResponse
if err := json.Unmarshal(body, &tokenResp); err != nil {
return "", fmt.Errorf("failed to process response as JSON: %w", err)
}
return tokenResp.Value, nil
}

// GetenvFunc is an abstraction to make tests feasible for commands that
// interact with environment variables.
type GetenvFunc func(k string) string
13 changes: 13 additions & 0 deletions actions_doc_test.go
Expand Up @@ -15,6 +15,8 @@
package githubactions_test

import (
"context"

"github.com/sethvargo/go-githubactions"
)

Expand Down Expand Up @@ -105,3 +107,14 @@ func ExampleAction_SetOutput() {
a := githubactions.New()
a.SetOutput("filepath", "/tmp/file-xyz1234")
}

func ExampleAction_GetIDToken() {
ctx := context.Background()

a := githubactions.New()
token, err := a.GetIDToken(ctx, "my-aud")
if err != nil {
// handle error
}
_ = token
}

0 comments on commit a712c2e

Please sign in to comment.